【jdk8新特性】方法引用
什么是方法引用,为什么要用方法引用
什么是方法引用
方法引用是为了简化lambda表达式而出现的,表现形式是A::B
为什么要用方法引用
我们来看一个例子就可以理解为什么要用方法引用
// 求一个数组的和
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) {
// 使用Lambda表达式求一个数组的和
/*printMax((int[] arr) -> {
getMax(arr);
});*/ // 例子一
// 使用方法引用
// 让这个指定的方法去重写接口的抽象方法,到时候调用接口的抽象方法就是调用传递过去的这个方法
printMax(Demo01MethodRefIntro::getMax);// 例子二
}
public static void printMax(Consumer<int[]> consumer) {
int[] arr = {11, 22, 33, 44, 55};
consumer.accept(arr);
}
}
我们可以看到我们有一个getMax方法进行数组求和运算,此时我们使用Lambda表达式来进行数组求和,可以看到第一个例子它用lambda调用了 getMax方法 但这样那我为什么不直接用getMax方法呢?所以我们有了例子二:利用类::方法名 来用作方法引用,即把方法名对应的方法 重写到accept方法。
常见引用方式
方法引用在JDK 8中使用方式相当灵活,有以下几种形式:
- instanceName::methodName 对象::方法名
- ClassName::staticMethodName 类名::静态方法
- ClassName::methodName 类名::普通方法
- ClassName::new 类名::new 调用的构造器
- TypeName[]::new String[]::new 调用数组的构造器
其中3:类名::普通方法,按传统语法的理解是错误的,这里进行了处理
对象名::引用成员方法
// 对象::实例方法
@Test
public void test01() {
Date now = new Date();
/*Supplier<Long> su1 = () -> {
return now.getTime();
};*/
// 使用方法引用
Supplier<Long> su1 = now::getTime;
Long aLong = su1.get();
System.out.println("aLong = " + aLong);
}
这里我们使用了Date类的实例对象 now进行方法引用
补充注意点
注意:方法引用有两个注意事项
1.被引用的方法,参数要和接口中抽象方法的参数一样 2.当接口抽象方法有返回值时,被引用的方法也必须有返回值 Supplier<Long> su3 = now::setTime;// 错误 su3.get();
Supplier su4 = now::setDate;
su4.get();
可以看出setTime与setDate都需要参数且不需要返回值,但get方法是由返回值不需要参数,因为本质是重写get方法,但现在参数、返回值 不匹配所有不能这样写。
类名::引用静态方法
// 类名::静态方法
@Test
public void test02() {
/*Supplier<Long> su = () -> {
return System.currentTimeMillis();
};*/
Supplier<Long> su = System::currentTimeMillis;
Long time = su.get();
System.out.println("time = " + time);
}
类名::引用实例方法
// 类名::实例方法
@Test
public void test03() {
/*Function<String, Integer> f1 = (String str) -> {
return str.length();
};*/
// 类名::实例方法(注意:类名::类名::实例方法实际上会将第一个参数作为方法的调用者)
Function<String, Integer> f1 = String::length;
int length = f1.apply("hello");// 调用的实际是"hello".length()
System.out.println("length = " + length);
// BiFunction<String, Integer, String> f2 = String::substring;
// 相当于这样的Lambda
BiFunction<String, Integer, String> f2 = (String str, Integer index) -> {
return str.substring(index);
};
String str2 = f2.apply("helloworld", 3);// 相当于"helloworld".substring(3);
System.out.println("str2 = " + str2); // loworld
}
Java面向对象中,类名只能调用静态方法,类名引用实例方法是有前提的,实际上是拿第一个参数作为方法的调用者。
类名::new引用构造器
// 类名::new引用类的构造器
@Test
public void test04() {
/*Supplier<Person> su1 = () -> {
return new Person();
};*/
Supplier<Person> su1 = Person::new;
Person person = su1.get();
System.out.println("person = " + person);
/*BiFunction<String, Integer, Person> bif = (String name, Integer age) -> {
return new Person(name, age);
};*/
BiFunction<String, Integer, Person> bif = Person::new;
Person p2 = bif.apply("凤姐", 18);
System.out.println("p2 = " + p2);
}
Person类
public class Person {
private String name;
private int age;
public Person() {
System.out.println("执行无参构造");
}
public Person(String name, int age) {
System.out.println("执行有参构造: " + name + ", " + age);
this.name = name;
this.age = age;
}
}
由于构造器的名称与类名完全一样。所以构造器引用使用 类名称::new 的格式表示。
数组::new 引用数组构造器
// 类型[]::new
@Test
public void test05() {
/*Function<Integer, int[]> f1 = (Integer length) -> {
return new int[length];
};*/
Function<Integer, int[]> f1 = int[]::new;
int[] arr1 = f1.apply(10);
System.out.println(Arrays.toString(arr1));
}
数组也是 Object 的子类对象,所以同样具有构造器,只是语法稍有不同。