一:Lambda的冗余场景
使用Lambda表达式求一个数组的和
public class Demo11MethodRefIntro {
public static void getMax(int[] arr) {
int sum = 0;
for (int n : arr) {
sum += n;
}
System.out.println(sum);
}
public static void main(String[] args) {
printMax((int[] arr) -> {
int sum = 0;
for (int n : arr) {
sum += n;
}
System.out.println(sum);
});
}
private static void printMax(Consumer<int[]> consumer) {
int[] arr = {10, 20, 30, 40, 50};
consumer.accept(arr);
}
}
体验方法引用简化Lambda
如果我们在
Lambda
中所指定的功能,已经有其他方法存在相同方案,那是否还有必要再写重复逻辑?可以直接
“
引用”
过去就好了
public class DemoPrintRef {
public static void getMax(int[] arr) {
int sum = 0;
for (int n : arr) {
sum += n;
}
System.out.println(sum);
}
//使用方法引用
//让这个指定的方法去重写接口的抽象方法,到时候调用接口的抽象方法就是调用传递过去的这个方法
public static void main(String[] args) {
printMax(Demo11MethodRefIntro::getMax);
}
private static void printMax(Consumer<int[]> consumer) {
int[] arr = {10, 20, 30, 40, 50};
consumer.accept(arr);
}
}
请注意其中的双冒号
::
写法,这被称为
“
方法引用
”
,是一种新的语法。
方法引用的格式
符号表示
:
::
符号说明
:
双冒号为方法引用运算符,而它所在的表达式被称为
方法引用
。
应用场景
:
如果
Lambda
所要实现的方案
,
已经有其他方法存在相同方案,那么则可以使用方法引用。
常见引用方式:
方法引用在
JDK 8
中使用方式相当灵活,有以下几种形式:
1.
instanceName::methodName
对象
::
方法名
2.
ClassName::staticMethodName
类名
::
静态方法
3.
ClassName::methodName
类名
::
普通方法
4.
ClassName::new
类名
::new
调用的构造器
5.
TypeName[]::new
String[]::new
调用数组的构造器
二:对象名::引用成员方法
这是最常见的一种用法,与上例相同。如果一个类中已经存在了一个成员方法,则可以通过对象名引用成员方法,代码为:
// 对象::实例方法
@Test
public void test01() {
Date now = new Date();
Supplier<Long> supp = () -> {
return now.getTime();
};
System.out.println(supp.get());
Supplier<Long> supp2 = now::getTime;
System.out.println(supp2.get());
}
方法引用的注意事项
1.
被引用的方法,参数要和接口中抽象方法的参数一样
2.
当接口抽象方法有返回值时,被引用的方法也必须有返回值
三:类名::引用静态方法
由于在
java.lang.System
类中已经存在了静态方法
currentTimeMillis
,所以当我们需要通过
Lambda
来调用该方法时,
可以使用方法引用
,
写法是:
// 类名::静态方法
@Test
public void test02() {
Supplier<Long> supp = () -> {
return System.currentTimeMillis();
};
System.out.println(supp.get());
Supplier<Long> supp2 = System::currentTimeMillis;
System.out.println(supp2.get());
}
四:类名::引用实例方法
Java
面向对象中,类名只能调用静态方法,类名引用实例方法是有前提的,实际上是拿第一个参数作为方法的调用者。
// 类名::实例方法
@Test
public void test03() {
Function<String, Integer> f1 = (s) -> {
return s.length();
};
System.out.println(f1.apply("abc"));
//类名::实例方法(实际上会将第一个参数作为方法的调用者)
Function<String, Integer> f2 = String::length;
System.out.println(f2.apply("abc"));
//两个参数,一个返回值
BiFunction<String, Integer, String> bif = String::substring;
String hello = bif.apply("hello", 2);
System.out.println("hello = " + hello);
}
五:类名::new引用构造器
由于构造器的名称与类名完全一样。所以构造器引用使用
类名称
::new
的格式表示。首先是一个简单的
Person
类:
public class Person {
private String name;
public Person(String name) {
this.name = name;
}
public String getName() {
return name;
}
}
要使用这个函数式接口,可以通过方法引用传递:
// 类名::new
@Test
public void test04() {
Supplier<Person> sup = () -> {
return new Person();
};
System.out.println(sup.get());
Supplier<Person> sup2 = Person::new;
System.out.println(sup2.get());
BiFunction<String, Integer, Person> fun2 = Person::new;
System.out.println(fun2.apply("张三", 18));
}
六:数组::new 引用数组构造器
数组也是 Object 的子类对象,所以同样具有构造器,只是语法稍有不同。
// 类型[]::new
@Test
public void test05() {
Function<Integer, String[]> fun = (len) -> {
return new String[len];
};
String[] arr1 = fun.apply(10);
System.out.println(arr1 + ", " + arr1.length);
Function<Integer, String[]> fun2 = String[]::new;
String[] arr2 = fun.apply(5);
System.out.println(arr2 + ", " + arr2.length);
}
小结
方法引用是对
Lambda
表达式符合特定情况下的一种缩写,它使得我们的
Lambda
表达式更加的精简,也可以理解为 Lambda表达式的缩写形式
,
不过要注意的是方法引用只能
"
引用
"
已经存在的方法
!