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中使用方式相当灵活,有以下几种形式:
- instanceName::methodName 对象::方法名
- ClassName::staticMethodName 类名:: 静态方法
- ClassName::methodName 类名::普通方法
- ClassName::new 类名::new 调用的构造器
- 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());
}
方法引用的注意事项
- 被引用的方法,参数要和接口中抽象方法的参数一样
- 当接口抽象方法有返回值时,被引用的方法也必须有返回值
类名::引用静态方法
由于在 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"));
Bi Function <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表达式的缩写形式 , 不过要注意的是方法引用只能”引用”已经存在的方法!