Java 8 中的方法引用
一、原理概要
lambda 表示式,可以作为某些匿名内部类的替代。主要目的是调用该内部类中的方法,而该方法的实现(重写)由 lambda表示式决定。
通常,我们可能不关心匿名内部类中的具体方法(被重写的方法),而只关心该方法是怎么被重写的(方法的实现)。因此,我们可以构造一个中间对象(通常是接口,比如 Funtion),该接口拥有一个需要该重写的方法(比如 Function 对应的方法是 apply)。
二、如何使用
在实际书写时,可以只写出(传递的参数)与{方法的实现},或者只标出实现过程的 调用者的和其方法名(使用双冒号分隔)。
Function<Person, Integer> getAge = Person::getAge;
// 传参数调用 getAge 方法
Integer age = getAge.apply(p);
注释:
1. 比如 Function<T,R>
,T
表示传入类型,R
表示返回类型。比如,表达式 person -> person.getAge();
,传入参数是 person
,返回值是 person.getAge()
,那么方法引用 Person::getAge
就对应着 Function<Person,Integer>
类型。
2. 使用双冒号的方式会返回这个对象,当你调用该对象中的 apply 方法时,就会调用你之前传进去的方法。
3. 这个过程类似一个函数的闭包。当你使用双冒号的方式,会把你的类和方法传入并生成一个 Function对象。该对象会在之后某个时间被调用,此时它会调用之前你传入这个对象中的方法。
三、什么情况下可以使用方法引用(双冒号)?
lambda 的两种方式对比
// old way
List<Integer> list = Arrays.asList(1, 2, 3, 4, 5, 6, 7);
for (Integer n : list) {
System.out.println(n);
} // 使用 -> 的 Lambda 表达式
list.forEach(n -> System.out.println(n)); // 使用 :: 的 Lambda 表达式
list.forEach(System.out::println);
list的 foreach 方法参数中有个函数式接口Consumer。该接口中
有个抽象方法 accept
能够接收一个参数但是没有返回值,这个时候我想实现accept
方法,让它的功能为打印接收到的那个参数,那么我可以使用Lambda表达式这么做
Consumer<String> consumer = str -> System.out.println(str);
consumer.accept("This is Major Tom");
但是类似的功能PrintStream
类(也就是System.out
的类型)的println
方法已经实现了,
Consumer<String> consumer = System.out::println;
consumer.accept("This is Major Tom");
这个类似之处就是 accept
方法跟println
方法都是接收一个参数类型为String
参数,并且无返回值。
这就是方法引用的规定,实现抽象方法的参数列表,必须与方法引用方法的参数列表保持一致!至于返回值就不作要求。
四、关于函数式接口
1. Java 8中允许接口实现方法, 而不是简单的声明。需要使用关键字 default
2. Java8 中的 函数式接口中除了定义抽象方法外还可以包含静态方法。
@FunctionalInterface
interface FunctionalInterfaceWithStaticMethod {
static int sum(int[] array) {
return Arrays.stream(array).reduce((a, b) -> a+b).getAsInt();
} void apply();
}
注. @FunctionalInterface注解,主要用于编译级错误检查,加上该注解,当你写的接口不符合函数式接口定义的时候,编译器会报错。
3.一般情况下函数式接口只会定义一个抽象方法,但是接口最终有确定的类实现, 而类的最终父类是Object。 因此函数式接口可以定义Object 中的public方法,protected 方法不行。
@FunctionalInterface
public interface ObjectMethodFunctionalInterface {
void count(int i); String toString(); //same to Object.toString
int hashCode(); //same to Object.hashCode
boolean equals(Object obj); //same to Object.equals
}
4. util 包中的函数式接口
java.util.function
中定义了几组类型的函数式接口以及针对基本数据类型的子接口。
- Predicate -- 传入一个参数,返回一个bool结果, 方法为
boolean test(T t)
- Consumer -- 传入一个参数,无返回值,纯消费。 方法为
void accept(T t)
- Function<t,r> -- 传入一个参数,返回一个结果,方法为
R apply(T t)
- Supplier -- 无参数传入,返回一个结果,方法为
T get()
- UnaryOperator -- 一元操作符, 继承Function<t,t>,传入参数的类型和返回类型相同。
- BinaryOperator -- 二元操作符, 传入的两个参数的类型和返回类型相同, 继承BiFunction
Java 8 中的方法引用的更多相关文章
- Java 8 中的方法引用,轻松减少代码量,提升可读性!
1. 引言 Java8中最受广大开发中喜欢的变化之一是因为引入了 lambda 表达式,因为这些表达式允许我们放弃匿名类,从而大大减少了样板代码,并提高了可读性. 方法引用是lambda表达式的一种特 ...
- Java8中的[方法引用]“双冒号”——走进Java Lambda(四)
前面的章节我们提及到过双冒号运算符,双冒号运算就是Java中的[方法引用],[方法引用]的格式是 类名::方法名 注意是方法名哦,后面没有括号“()”哒.为啥不要括号,因为这样的是式子并不代表一定会调 ...
- Swift编程语言中的方法引用
由于Apple官方的<The Swift Programming Guide>对Swift编程语言中的方法引用介绍得不多,所以这里将更深入.详细地介绍Swift中的方法引用. Swift与 ...
- thymeleaf模板引擎调用java类中的方法(附源码)
前言 <Docker+SpringBoot+Mybatis+thymeleaf的Java博客系统开源啦> 由于开源了项目的缘故,很多使用了My Blog项目的朋友遇到问题也都会联系我去解决 ...
- Jsp中如何通过Jsp调用Java类中的方法
Jsp中如何通过Jsp调用Java类中的方法 1.新建一个项目,在src文件夹下添加一个包:如:cn.tianaoweb.com; 2.再在包中添加一个类:如 package com; public ...
- java中的方法引用(method reference)官方文档总结
2017/7/5 转载写明出处:http://www.cnblogs.com/daren-lin/p/java-method-reference.html 今天要说的是java中的一项新特性,方法引用 ...
- java中的方法引用
引用静态方法:类名称::static 方法名称: 引用某个对象的方法:对象::普通方法: 引用特定类方法:特定类::方法 引用构造方法:类名称::new 范例:引用静态方法 package com.j ...
- 第6章 Java类中的方法
1.如何定义java的方法 什么是方法:方法使用来解决一类问题的代码集合,是一个功能模块在类中定义个方法的方法是: 访问修饰符 返回值类型 方法名(参数列表){ 方法体 } 1.访问修饰符,是限制该方 ...
- java String 中 intern方法的概念
1. 首先String不属于8种基本数据类型,String是一个对象. 因为对象的默认值是null,所以String的默认值也是null:但它又是一种特殊的对象,有其它对象没有的一些特性. 2. ne ...
随机推荐
- python接口自动化29-requests-html支持JavaScript渲染页面
前言 requests虽好,但有个遗憾,它无法加载JavaScript,当访问一个url地址的时候,不能像selenium一样渲染整个html页面出来. requests-html终于可以支持Java ...
- bootstrap3-iframe-modal子页面在父页面显示模态框
本文灵感来自:http://www.cnblogs.com/chengxuyuanzhilu/p/5132328.html 子页面内容 //打开模态框 function openMySelectMod ...
- Glide终于解决了同时绑定多个webp格式图片的问题
前端时间,要给项目换个图片加载的库,使用Glide 3.7版本进行测试, 发现在快速滑动列表(每个item都会加载一个app的图标,采用webp格式,即同时加载多个webp格式)的时候,一屏至少有2- ...
- TFS online build change web.config
概要 TFS online 自动编译时如何修改web.config ref:https://dustinoprea.com/2016/05/06/using-tokenization-token-re ...
- 【nginx&php】后台权限认证方式
一.最常用的方法(代码中限制) 1.如何限制IP function get_new_ip(){ if(getenv('HTTP_CLIENT_IP')) { $onlineip = getenv('H ...
- IOS开发中xib和StoryBoard的优缺点
总所周知,苹果官方为IOS开发提供了3种制作UI方式,让我们能够快速开发漂亮APP界面,每一种方式都有他们各自的特点,谁也不能代替谁.但是国内开发人员为此时争得不可开交. 大家各说各有理,说都想说服谁 ...
- Servlet中的request对象、重定向和转发的差别(6)
1.这里所说的request对象指的是HttpServletRequest对象,它代表client的请求,当client通过HTTP协议訪问server时.HTTP请求头中的全部信息都封装在这个对象中 ...
- android sdk content loader 0%不动
Make sure that eclipse is not active. If it is active kill eclipse from the processes tab of the tas ...
- sublime Text3基本配置记录+python
环境:ubuntu 内容:基本配置+python开发实用插件 一. 激活 注册码 Michael Barnes Single User License EA7E- 8A353C41 872A0D5C ...
- QT信号/槽
在我的理解中,QT和Android都是类似的开发框架,都是由开发团队封装了各式各样的接口和数据结构.将一些问题的解决方法简单化比如QT中将线程封装为QThread,派生类通过重写run方法来将代码投入 ...