lambda 表达式
lambda 表达式就是一个代码块, 以及必须传人代码的变量规范。
(String first, String second) -> first.length()- second.length()
如果代码要完成的计算无法放在一个表达式中,就可以像写方法一样,把这些代码放在 {}中,并包含显式的 return语句
(String first, String second) -> {
if (first.length() < second.length()) return -1;
else if (first.length() > second.length()) return 1;
else return 0;
}
即使 lambda 表达式没有参数, 仍然要提供空括号,就像无参数方法一样:
() -> { for (int i = 100;i >= 0;i-- ) System.out.println(i); }
如果方法只有一 参数, 而且这个参数的类型可以推导得出,那么甚至还可以省略小括号
ActionListener listener = event ->
System.out.println("The time is " + new Date()");
// Instead of (event) -> . . . or (ActionEvent event) -> . . .
无需指定 lambda 表达式的返回类型。lambda 表达式的返回类型总是会由上下文推导得出
(String first, String second) -> first.length() - second.length()
如果一个 lambda 表达式只在某些分支返回一个值, 而在另外一些分支不返回值,这是不合法的。
在 Java 中, 对 lambda 表达式所能做的也只是能转换为函数式接口。
java.util.function 包中有一个尤其有用的接口 Predicate:
public interface Predicate<T> {
boolean test(T t); // Additional default and static methods
}
ArrayList 类有一个 removelf 方法, 它的参数就是一个 Predicate。这个接口专门用来传递lambda 表达式。例如,下面的语句将从一个数组列表删除所有 null 值:
list.removelf(e -> e == null);
方法引用
有时, 可能已经有现成的方法可以完成你想要传递到其他代码的某个动作。
Timer t = new Timer(1000, System.out::println);
表达式 System.out::println 是一个方法引用( method reference ), 它等价于 lambda 表达式
x 一> System.out.println(x)。
构造器引用
构造器引用与方法引用很类似,只不过方法名为 new。
假设你有一个字符串列表。可以把它转换为一个 Person 对象数组,为此要在各个字符串上调用构造器,调用如下:
ArrayList<String> names = . . .;
Stream<Person> stream = names.stream().map(Person::new);
List<Person> people = stream.col1ect(Collectors.toList());
Java 有一个限制,无法构造泛型类型 T 的数组。数组构造器引用对于克服这个限制很有
用。表达式 new T[n] 会产生错误,因为这会改为 new Object[n]。例如,假设我们需要一个 Person 对象数组。Stream 接口有一个 toArray 方法可以返回 Object 数组:
Object[] people = stream.toArray();
用户希望得到一个 Person 引用数组,而不是 Object 引用数组。流库利用构造器引用解决了这个问题。可以把 Person[]::new 传人 toArray 方法:
Person[] people = stream.toArray(Person[]::new):
lambda 表达式有 3个部分:
1 ) 一个代码块;
2 ) 参数;
3 ) 自由变量的值, 这是指非参数而且不在代码中定义的变量。
lambda 表达式中捕获的变量必须实际上是最终变量 ( effectively final)。实际上的最终变量是指, 这个变量初始化之后就不会再为它赋新值。在这里,text 总是指示同一个String 对象,所以捕获这个变量是合法的。不过,i 的值会改变,因此不能捕获i。
public static void repeat(String text, int count) {
for (int i = 1; i <= count; i++) {
ActionListener listener = event -> {
System.out.println(i + ": " + text);
// Error: Cannot refer to changing
};
new Timer(1000, listener).start();
}
}