【Java】lambda表达式和方法引用详解(jdk1.8新特性)
1、lambda表达式(jdk1.8)
lambda表达式是用来简化函数式接口的匿名内部类的写法的。
在Java编程语言中,匿名内部类是一个特殊的类,它没有明确的类名,通常用于简化代码和实现接口。匿名内部类的定义位于一个类的局部位置,例如方法中或代码块中。
函数式接口在Java中是指仅有一个抽象方法的接口。这种接口可以用作函数式参数、返回值或者赋值给函数式变量。大部分函数式接口上可能都会有一个@FunctionalInterface
的注解。
lambda表达式写法如下:
函数式接口 名称=(参数)->{
//函数式接口唯一方法的实现
}
当匿名内部类的引用传递给接口类型或者抽象类类型,如果发现类型是函数式接口,那很明显匿名内部类重写的方法必定是函数式接口的唯一方法,因此,匿名内部类的写法可以得到简化。
由此也可以看出,并不是所有匿名内部类都能使用lambda表达式。只有函数式接口才能使用lambda表达式。
一个将函数式接口的匿名内部类化为lambda表达式的完整例子:
//匿名内部类
Comparator<Integer> comparator = new Comparator<Integer>() {
@Override
public int compare(Integer num1, Integer num2) {
// 比较两个整数的大小
return num1 - num2;
}
};
//函数式接口
Comparator<Integer> comparator = (num1, num2) -> {return num1 - num2;};
lambda表达式在某些情况下可以略写。以下是lambda表达式的省略规则。
- 参数类型可以省略不写
- 如果只有一个参数,参数的括号可以省略不写
- 如果lambda表达式中的方法体代码中只有一行代码,可以省略方法体的大括号不写(同时要省略这行代码的分号),此时如果这行代码是return语句,也必须要把return语句省略掉。
2、方法引用(jdk1.8)
lambda表达式是对函数式接口的匿名内部类的简化,那lambda表达式之中创建的对象、调用的方法是否有机会进行简化呢?这就是方法引用。
方法引用的目的是为了进一步简写lambda表达式。它的标志性符号是::
。
方法引用可以分为静态方法引用、实例方法引用、特定类型的方法引用以及构造器引用。
2.1、静态方法引用
如果某个lambda表达式中,只有一个类调用了它的静态方法,并且传入静态方法的参数与lambda表达式的参数类型一致,那么可以使用方法引用进行简化。
public class Main {
public static void main(String[] args) {
ArrayList<Integer> list = new ArrayList<>();
list.add(5);
list.add(10);
list.add(1);
//lambda表达式中只调用了CompareData的一个静态方法,可用静态引用进行简写
Collections.sort(list,CompareData::compare);
System.out.println(list);
}
}
class CompareData{
public static int compare(int o1,int o2){
return o1-o2;
}
}
2.2、实例方法引用
如果一个静态方法中只是调用一个实例方法,并且传入实例方法的参数与lambda表达式类型一致,就可以使用实例方法引用。
与上边的静态引用不同,如果想要对实例方法进行引用,需要先创建一个对象。
public class Main {
public static void main(String[] args) {
ArrayList<Integer> list = new ArrayList<>();
list.add(5);
list.add(10);
list.add(1);
CompareData compareData = new CompareData();
Collections.sort(list,compareData::compareDesc);
System.out.println(list);
}
}
class CompareData{
public int compareDesc(int o1,int o2){
return o2-o1;
}
}
2.3、特定类型方法引用
这种比较特殊。假设lambda表达式有两个参数o1、o2,如果表达式中,o1调用了一个方法,o2作为该方法的入参,那么可以简写。
如何简写?o1的类进行方法引用。
public class Main {
public static void main(String[] args) {
List<String> list = Arrays.asList("a", "b", "c");
Collections.sort(list, new Comparator<String>() {
@Override
public int compare(String o1, String o2) {
//无视大小写进行比较
return o1.compareToIgnoreCase(o2);
}
});
//使用lambda表达式,可以简写为:
Collections.sort(list, (o1, o2) -> o1.compareToIgnoreCase(o2));
//o1调用方法,o2入参,可以继续简写为:
Collections.sort(list, String::compareToIgnoreCase);
}
}
2.4、构造器引用
如果某个lambda表达式只是在创建对象,并且lambda表达式与构造方法参数情况一致,就可以使用构造器引用。
public class Main {
public static void main(String[] args) {
CreateCar cc1 = new CreateCar() {
@Override
public Car create(String name, int price) {
return new Car(name, price);
}
};
//函数式接口,可以用lambda表达式简化
CreateCar cc2 = (name, price) -> new Car(name, price);
//lambda表达式中只进行了new的操作,还可以使用方法引用进行简化
CreateCar cc3 = Car::new;
}
}