lambda表达式的基本用法:
Arrays.sort(array, (s1, s2) -> s1.compareTo(s2));
参数是(s1, s2),参数类型可以省略,因为编译器可以自动推断出String类型。-> { … }表示方法体,所有代码写在内部即可。
我们把只定义了单方法的接口称之为FunctionalInterface,用注解@FunctionalInterface标记。
接收FunctionalInterface作为参数的时候,可以把实例化的匿名类改写为Lambda表达式,能大大简化代码。
想要用lambda表达式做一些处理,可以为它建立一个特定的函数式接口。java.util.function包中有一个很有用的接口Predicate:
public interface Predicate<T> {
boolean test(T t);
}
ArrayList有一个removeIf方法,它的参数就是一个Predicate,这个接口专门用于传递lambda表达式。比如:
list.removeIf(e -> e==null);
这个代码会删除集合中所有的null值。
default用于函数式接口的方法中,可以定义方法的默认实现
@FunctionalInterface
interface Interface1 {
int doubleNum(int i);
default int add(int x, int y) {
return x + y;
}
static int sub(int x, int y) {
return x - y;
}
}
方法引用指示编译器生成一个函数式接口的实例,覆盖这个接口的抽象方法来调用给定的方法。
public class Main {
public static void main(String[] args) {
String[] array = new String[] { "Apple", "Orange", "Banana", "Lemon" };
Arrays.sort(array, Main::cmp);
System.out.println(String.join(", ", array));
}
static int cmp(String s1, String s2) {
return s1.compareTo(s2);
}
}
方法引用的基本语法是:类::方法
引用构造方法是:类::new
只有当lambda表达式的体只调用一个方法而不做其他操作时,才把lambda表达式重写为方法引用。比如s -> s.length() == 0,这里因为还有一个比较,所以不能使用方法引用。
lambda表达式可以引用外围方法或者类中的变量,但是引用的变量必须是事实最终变量,也就是说这个变量初始化后就不会再为它赋新值。lambda表达式中不能有同名的局部变量。lambda表达式中的this是只创建lambda表达式的方法的this。
方法要接受一个lambda表达式,需要一个函数式接口。java API中提供了一些常用的函数式接口可以使用,比如Runnable接口,使用Runnable接口如下:
public static void repeat(int n, Runnable action) {
for (int i=0; i < n; i++) action.run();
}
调用这个方法:
repeat(10, () -> System.out.println("Hello World!"));
Stream中可以“存储”有限或无限个集合,存储在Stream中的可以是java对象,存储在Stream中的元素或者对象可以进行变化,但是这种变化并没有发生计算,只有在最后要取出元素或对象使用时计算才会发生,是一种惰性计算。