JDK8新特性---方法引用
什么是方法引用呢?
其实这个东西,在我之前的文章已经有写到,但是,也只是写到,我没有详细的说明,现在我们来看一个例子
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
public class FunctionRefTest1 {
public static void main(String[] args) {
List<Student> list = new ArrayList<>();
list.add(new Student("张三",20));
list.add(new Student("李四",19));
list.add(new Student("王五",23));
list.add(new Student("刘六",22));
//通过Comparator对list排序
// lambda的简略写法
// list.sort((o1,o2)-> o1.getAge()-o2.getAge());
// lambda最简单的写法
list.sort( Comparator.comparingInt(Student::getAge));
for (Student student : list) {
System.out.println(student.getName()+" "+student.getAge());
}
}
}
在代码中,我们可以发现,list.sort((o1,o2)-> o1.getAge()-o2.getAge());
和list.sort( Comparator.comparingInt(Student::getAge));
这两段代码的效果是一样的,而list.sort( Comparator.comparingInt(Student::getAge));
这个就是使用了方法引用,效果是什么呢?方法引用使得lambda表达式不显得那么冗余,也就是简化了lambda表达式的写法格式。
初步体验
- 方法引用可以理解为消除lambda表达式的冗余问题,简化书写(还有点小装逼的意味在里面,你看得懂,别人看不懂,就可以装逼)
- 格式:
AA::BB
具体AA是什么,BB是什么,就要看具体情况了,下面我会详细说明
可能你现在还是蒙蒙的,没事,再来一个例子,让你消化一下
public class FunctionRefTest2 {
public static void main(String[] args) {
getSum((a)->{
int ans = 0;
for (int i : a) {
ans += i;
}
System.out.println("sum = "+ans);
});
}
public static void getSum(Consumer<int[]> consumer){
int[] a = {1,2,3,4,5,6,7,8,9};
consumer.accept(a);
}
}
在这里我们要实现数组求和,我们这样写没问题,但是我们会发现lambda{}内的内容很多,而且,如果在外面有个方法也可以实现数组求和,就像这样
public class FunctionRefTest2 {
public static void main(String[] args) {
getSum((a)->{
int ans = 0;
for (int i : a) {
ans += i;
}
System.out.println("sum = "+ans);
});
}
public static void sum(int[] a){
int ans = 0;
for (int i : a) {
ans += i;
}
System.out.println("sum = "+ans);
}
public static void getSum(Consumer<int[]> consumer){
int[] a = {1,2,3,4,5,6,7,8,9};
consumer.accept(a);
}
}
外面的sum
方法和lambda表达式的{}
内的代码就重复了,这样就出现了lambda表达式冗余的情况了,这时候,方法引用就发挥了它的作用
public class FunctionRefTest2 {
public static void main(String[] args) {
getSum(FunctionRefTest2::sum);
}
public static void sum(int[] a){
int ans = 0;
for (int i : a) {
ans += i;
}
System.out.println("sum = "+ans);
}
public static void getSum(Consumer<int[]> consumer){
int[] a = {1,2,3,4,5,6,7,8,9};
consumer.accept(a);
}
}
怎么样,lambda表达式是不是更简洁了,逼格更高了?相信到这里,你已经对方法引用已经有一些了解了,接下来,让我们再去看看它的其他内容
方法引用的方式
- 对象名::方法名
- 类名::静态方法名
- 类名::引用实例方法
- 类名::构造器
- 数组::构造器
方法引用的注意事项:
- 被引用的方法,参数要和接口中的抽象方法的参数—样
- 当接口抽象方法有返回值时,被引用的方法也必须有返回值
- 方法引用只能引用已经存在的方法
没有实例怎么行呢,来几个实例看看,深入了解一下
对象名::方法名
这是最常见的一种用法。如果一个类中的已经存在了一个成员方法,则可以通过对象名引用成员方法
package com.features.functionReference;
import java.util.Date;
import java.util.function.Supplier;
public class FunctionRefTest3 {
public static void main(String[] args) {
Date now = new Date();
Supplier<Long> s1 = () -> now.getTime();
System.out.println("未使用方法引用得到的当前时间:"+s1.get());
Supplier<Long> s2 = now::getTime;
System.out.println("使用方法引用得到的当前时间:"+s2.get());
}
}
now是Date类型的一个对象
类名::静态方法名
常见的形式之一
package com.features.functionReference;
import java.util.function.Supplier;
// 类名::静态方法名
public class FunctionRefTest4 {
public static void main(String[] args) {
Supplier<Long> s1 = ()-> System.currentTimeMillis();
System.out.println("未使用方法引用得到的当前时间:"+s1.get());
Supplier<Long> s2 = System::currentTimeMillis;
System.out.println("未使用方法引用得到的当前时间:"+s2.get());
}
}
System是一个类
类名::引用实例方法
Java面向对象中,类名只能调用静态方法,类名引用实例方法是用前提的,实际上是拿第一个参数作为方法的调用者
package com.features.functionReference;
import java.util.function.BiFunction;
import java.util.function.Function;
// 类名::引用实例方法
public class FunctionRefTest5 {
public static void main(String[] args) {
Function<String,Integer> f1 = s -> s.length();
System.out.println("未使用方法引用得到的hello的长度为:"+f1.apply("hello"));
Function<String,Integer> f2 = String::length;
System.out.println("使用方法引用得到的hello的长度为:"+f2.apply("hello"));
BiFunction<String,Integer,String> f3 = String::substring;
System.out.println("使用方法引用得到的hello的长度为:"+f3.apply("hello",2));
}
}
s是String的一个实例,而length是s的实例方法
类名::构造器
由于构造器的名称和类名完全一致,所以构造器引用使用:: new
的格式使用,
package com.features.functionReference;
import com.features.lambda.demo02.Student;
import java.util.function.BiFunction;
import java.util.function.Supplier;
// 类名::构造器
public class FunctionRefTest6 {
public static void main(String[] args) {
Supplier<Student> s1 = () -> new Student();
System.out.println("未使用方法引用前得到的结果:"+s1.get());
Supplier<Student> s2 = Student::new;
System.out.println("使用方法引用后得到的结果:"+s2.get());
BiFunction<String,Integer,Student> function = Student::new;
System.out.println("使用方法引用后得到的结果:"+function.apply("张三",20));
}
}
Student是一个具体的类
数组::构造器
package com.features.functionReference;
import java.util.function.Function;
// 数组::构造器
public class FunctionRefTest7 {
public static void main(String[] args) {
Function<Integer,String[]> f1 = len->new String[len];
System.out.println("未使用方法引用前得到的数组的长度:"+f1.apply(5).length);
Function<Integer,String[]> f2 = String[]::new;
System.out.println("使用方法引用后得到的数组的长度:"+f2.apply(5).length);
}
}