什么是方法引用?
答:方法引用是对Lambda表达式符合某种情况下的一种缩写,使得我们的Lambda表达式更加的精简,也可以理解为Lambda表达式的另一种表现形式(缩写)
什么时候使用方法引用呢?
答:当要传递给Lambda体内的操作,已经有实现的方法了,就可以使用方法引用了
方法引用使用的前提条件是什么呢?
答:
1.方法引用所引用的方法的参数列表必须要和函数式接口中抽象方法的参数列表相同(完全一致)
2.方法引用所引用的方法的的返回值必须要和函数式接口中抽象方法的返回值相同(完全一致)
方法引用有什么语法格式吗?方法引用一般有三种格式:
-
实例对象名::实例方法名
-
类名::静态方法名
-
类名::实例方法名 (注意区别2,3的区别,下面会说)
2,3的区别:
若Lambda 的参数列表的第一个参数,是实例方法的调用者,第二个参数(或无参)是实例方法的参数时,格式: 类名::实例方法名
举例一:1. 实例对象名::实例方法名(案例一)
public class Student {
private String name;
private int age;
public Student(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public static void main(String[] args) {
Student student = new Student("XiangYang",23);
Supplier<String> supplier = ()->student.getName();
System.out.println("Lambda形式: "+supplier.get());
Supplier<String> supplier1 = student :: getName;
System.out.println("方法引用形式: "+supplier1.get());
}
}
举例一: 1. 实例对象名::实例方法名 (案例二)
public class Test06 {
public void test06(){
//传统Lambda表达式
Consumer<String> consumer = (x) -> System.out.println(x);
consumer.accept("Hi: 我是Lambda表达式实现的!"); //打印:Hi: 我是Lambda表达式实现的!
//方法引用实现
consumer =System.out::println;
consumer.accept("Hello : XiangYang,我是使用方法引用实现的 ");//打印:Hello : XiangYang,我是使用方法引用实现的
}
}
举例二: 2. 类名::静态方法名
@Test
public void test8() {
//传统Lambda表达式
Consumer<String> consumer = (str) -> sop(str);
consumer.accept("Hello : XiangYang"); //打印:Hello : XiangYang
//方法引用方式
consumer = Test06::sop;
consumer.accept("Hello : XiangYang"); //打印:Hello : XiangYang
}
private static void sop(String str) {
System.out.println(str);
}
举例三: 3. 类名::实例方法名
@Test
public void test7(){
//传统Lambda表达式
BiPredicate<String,String> biPredicate = (x, y) -> x.equals(y);
boolean test = biPredicate.test("hello", "hi");
System.out.println(test);//false
//方法引用
biPredicate = String::equals;
test = biPredicate.test("hello", "hello");
System.out.println(test);//true
}
注意:
方法引用总结:
1.一定弄明白使用方法引用的前提条件(2个)
a. 方法引用所引用的方法的参数列表必须要和函数式接口中抽象方法的参数列表相同(完全一致)
b .方法引用所引用的方法的的返回值必须要和函数式接口中抽象方法的返回值相同(完全一致)
这里使用代码解释一下:
@org.junit.Test
public void test6(){
//传统Lambda表达式
Consumer<String> consumer = (x) -> System.out.println(x);
consumer.accept("Hi: 我是Lambda表达式实现的!"); //打印:Hi: 我是Lambda表达式实现的!
//方法引用实现
consumer = System.out::println;
consumer.accept("Hello : XiangYang,我是使用方法引用实现的 ");//打印:Hello : XiangYang,我是使用方法引用实现的
}
解释:
1.首先我们看一下Consumer的函数式接口的源码的接口
void accept(T t);
由于我们给泛型传入的是String类型
Consumer<String> consumer = (x) -> System.out.println(x);
所以此时
//这是函数式接口中抽象方法,接收了实际类型String,没有返回值
void accept(T t); ==》 void accept(String t);
2 我们在看我们的Lambda体内的实现
System.out.println(x);
此时,我们查看println方法的源码:
//这是 方法引用所引用的方法 的参数类型是String,无返回值
public void println(String x) {
synchronized (this) {
print(x);
newLine();
}
}
3. 此时函数式的接口中的参数类型与返回值 和 方法引用所引用方法的参数类型与返回值相同,所以可以使用方法引用,类型为: 实例对象名:: 实例方法名
与匿名类相比,lambda表达式的主要优势在于他们更简洁。
map.merge(key, 1, (count, incr) -> count + incr);
请注意,此代码使用 merge 方法,该方法已添加到 Java 8 中的 Map 接口中。如果没有给定键的映射,则该方法只是插入给定值; 如果映射已经存在,则合并给定函数应用于当前值和给定值,并用结果覆盖当前值。
从 Java 8 开始,Integer 类(和所有其他包装数字基本类型)提供了一个静态方法总和,和它完全相同。 我们可以简单地传递一个对这个方法的引用,并以较少的视觉混乱得到相同的结果:
map.merge(key, 1, Integer::sum);
如果Lambda太长或者太复杂,方法引用还为我们提供一个解决方案:可以将代码从Lambda表达式中提取到一个新的方法中,并用指向方法的引用来替换这个Lambda表达式。我们可以给这个方法起个好的名字,并将内心的想法写在文档中。
例如,考虑这段代码,它被假定出现在一个名为 GoshThisClassNameIsHumongous
的类中:
service.execute(GoshThisClassNameIsHumongous::action);
这个 lambda 类似于等价于下面的代码:
service.execute(() -> action());
使用方法引用的代码段并不比使用 lambda 的代码片段更短也不清晰,所以优先选择后者。
许多方法引用是指静态方法,但有 4 种方法没有引用静态方法。 其中两个 Lambda 等式是特定(bound)和任意(unbound)对象方法引用。 在特定对象引用中,接收对象在方法引用中指定。 特定对象引用在本质上与静态引用类似:函数对象与引用的方法具有相同的参数。 在任意对象引用中,接收对象在应用函数对象时通过方法的声明参数之前的附加参数指定。 任意对象引用通常用作流管道(pipelines)中的映射和过滤方法(条目 45)。 最后,对于类和数组,有两种构造方法引用。 构造方法引用用作工厂对象。 下表总结了所有五种方法引用:
|------------------------|------------------------|-----------------------------------------------------|
| 方法引用类型 Method Ref Type | 举例 Example | Lambda 等式 Lambda Equivalent |
| Static | Integer::parseInt | str -> Integer.parseInt(str) |
| Bound | Instant.now()::isAfter | Instant then = Instant.now(); t -> then.isAfter(t) |
| Unbound | String::toLowerCase | str -> str.toLowerCase() |
| Class Constructor | TreeMap<K, V>::new | () -> new TreeMap<K, V> |
| Array Constructor | int[]::new | len -> new int[len] |
总而言之,方法引用通常为 lambda 提供一个更简洁的选择。 如果方法引用看起来更简短更清晰,请使用它们;否则,还是坚持 lambda表达式。
所有文章无条件开放,顺手点个赞不为过吧!