Lambda表达式: (Apple a1, Apple a2) -> { a1.getWeight().compareTo(a2.getWeight()) }
参数列表 —— 这里它采用了Comparator中compare方法的参数,两个Apple。
箭头 —— ‘->’把参数列表与Lambda主体分隔开。
Lambda主体 —— 比较两个Apple的重量。表达式就是Lambda的返回值了。
① 函数式接口
public interface Predicate{
boolean test (T t);
}
public interface Comparator {
int compare(T o1, T o2);
}
public interface Runnable{
void run();
}
public interface ActionListener extends EventListener {
void actionPerformed(ActionEvent e);
}
public interface Callable{
V call();
}
public interface PrivilegedAction{
V run();
}
② 环绕执行模式
// 这段代码是有局限的。只能读文件的第一行
public static String processFile() throws IOException {
// 带资源的try语句,不需要显式地关闭资源
try (BufferedReader br = new BufferedReader(new FileReader("data.txt"))) {
return br.readLine();
}
}
// 使用函数式接口来传递行为
public interface BufferedReaderProcessor {
String process(BufferedReader b) throws IOException;
}
// 执行一个行为
public static String processFile(BufferedReaderProcessor p) throws IOException {
try (BufferedReader br = new BufferedReader(new FileReader("data.txt"))) {
return p.process(br);
}
}
// 传递Lambda
// 处理一行
// String oneLine = processFile((BufferedReader br) -> br.readLine());
// 处理两行:
// String twoLines = processFile((BufferedReader br) -> br.readLine() + br.readLine());
③ 例子:Function
// 该接口接收两个泛型参数T,R;apply方法接收参数T,返回值类型为R
public interface Function{
R apply(T t);
}
public static List map(List list, Function f) {
List result = new ArrayList();
for(T s: list){
result.add(f.apply(s));
}
return result;
}
// [7, 2, 6]
// List l = map( Arrays.asList("lambdas","in","action"), (String s) -> s.length());
④ 使用局部变量
Lambda表达式也允许使用自由变量(不是参数,而是在外层作用域中定义的变量),就像匿名类一样。 它们被称作捕获Lambda
但局部变量必须显式声明为final,或事实上是final。
int portNumber = 1337;
// Runnable r = () -> System.out.println(portNumber);
// 下面的代码无法编译,因为portNumber变量被赋值两次
int portNumber = 1337;
Runnable r = () -> System.out.println(portNumber);
portNumber = 31337;
⑤ 方法引用
当需要使用方法引用时,目标引用放在分隔符::前,方法的名称放在后面。
例如,Apple::getWeight就是引用了Apple类中定义的方法getWeight。不需要括号,因为没有实际调用这个方法。
方法引用就是Lambda表达式(Apple a) -> a.getWeight()的快捷写法。
可以把方法引用看作针对仅仅涉及单一方法的Lambda的语法糖,因为你表达同样的事情时要写的代码更少了
List str = Arrays.asList("a","b","A","B");
str.sort((s1, s2) -> s1.compareToIgnoreCase(s2));
str.sort(String::compareToIgnoreCase);
⑥ 构造函数的引用
对于一个现有构造函数,你可以利用它的名称和关键字new来创建它的一个引用:ClassName::new。它的功能与指向静态方法的引用类似
// 利用默认构造函数创建Apple的Lambda表达式
// Supplier c1 = () -> new Apple();
// 构造函数引用指向默认的Apple()构造函数
// Supplier c1 = Apple::new;
// 如果你的构造函数的签名是Apple(Integer weight),利用默认构造函数创建Apple的Lambda表达式
// Function c2 = (weight) -> new Apple(weight);
// 指向Apple(Integer weight)的构造函数引用
// Function c2 = Apple::new;
⑦ Lambda 和方法引用实战
// 第1 步:传递代码
public class AppleComparator implements Comparator {
public int compare(Apple a1, Apple a2){
return a1.getWeight().compareTo(a2.getWeight());
}
}
inventory.sort(new AppleComparator());
// 第2 步:使用匿名类
inventory.sort(new Comparator() {
public int compare(Apple a1, Apple a2){
return a1.getWeight().compareTo(a2.getWeight());
}
});
// 第3 步:使用Lambda 表达式
inventory.sort((Apple a1, Apple a2) -> a1.getWeight().compareTo(a2.getWeight()));
// Java编译器可以根据Lambda出现的上下文来推断Lambda表达式参数的类型。以上代码可以重写成这样:
// inventory.sort((a1, a2) -> a1.getWeight().compareTo(a2.getWeight()));
// Comparator具有一个叫作comparing的静态辅助方法,它可以接受一个Function来提取Comparable键值,并生成一个Comparator对象
// Comparator c = Comparator.comparing((Apple a) -> a.getWeight());
// 可以把代码再改得更紧凑一点
// import static java.util.Comparator.comparing;
// inventory.sort(comparing((a) -> a.getWeight()));
// 第4 步:使用方法引用
// inventory.sort(comparing(Apple::getWeight));