1.1 Lambda 定义:
把Lambda表达式理解为简洁地表示可传递的匿名函数的一种方式:它没有名称,但它有参数列表、函数主体、返回类型,可能还有一个可以抛出的异常列表。
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.ToString;
@Data
@NoArgsConstructor
@AllArgsConstructor
@ToString
public class Apple {
private String name;
private String color;
private Double weight;
}
匿名类表示:
Comparator<Apple> byWeight1 = new Comparator<Apple>(){
@Override
public int compare(Apple o1, Apple o2) {
return o1.getWeight().compareTo(o2.getWeight());
}
};
修改为Lambda表示:
Comparator<Apple> byWeight2 = (Apple o1, Apple o2)-> o1.getWeight().compareTo(o2.getWeight());
是不是简洁了很多?
1.2 Lambda表达式有三个部分
2.1 函数式接口: 函数式接口就是只定义一个抽象方法的接口
下面三个接口都是函数式接口
@FunctionalInterface
public interface Comparator<T> {
int compare(T o1, T o2);
}
@FunctionalInterface
public interface Callable<V>{
V call();
}
public interface PrivilegedAction<T> {
T run();
}
用函数式接口可以干什么呢?Lambda表达式允许你直接以内联的形式为函数式接口的抽象方法提供实现,并把整个表达式作为函数式接口的实例(具体说来,是函数式接口一个具体实现的实例)。
下面代码有效:
//Lambda表达式
Runnable r2 = ()-> System.out.println("hello");
//匿名内部类
Runnable r1 = new Runnable() {
@Override
public void run() {
System.out.println("hello");
}
};
2.2 函数描述符
函数式接口的抽象方法的签名基本上就是Lambda表达式的签名。我们将这种抽象方法叫作函数描述符。
2.3 @FunctionalInterface 又是怎么回事
描述如下:
3. 把 Lambda 付诸实践:环绕执行模式
让我们通过一个例子,看看在实践中如何利用Lambda和行为参数化来让代码更为灵活,更为简洁。资源处理(例如处理文件或数据库)时一个常见的模式就是打开一个资源,做一些处理,然后关闭资源。这个设置和清理阶段总是很类似,并且会围绕着执行处理的那些重要代码。这就是所谓的环绕执行(execute around)模式
在以下代码中,高亮显示的就是从一个文件中读取一行所需的模板代码
/**
* 现在这段代码是有局限的。你只能读文件的第一行。如果你想要返回头两行,甚至是返回使
* 用最频繁的词,该怎么办呢?
* @return
* @throws IOException
*/
public static String processFile() throws IOException {
try(BufferedReader br = new BufferedReader(new FileReader("data.txt"))){
return br.readLine();
}
}
现在这段代码是有局限的。你只能读文件的第一行。如果你想要返回头两行,甚至是返回使用最频繁的词,该怎么办呢?在理想的情况下,你要重用执行设置和清理的代码,并告诉processFile 方法对文件执行不同的操作。这听起来是不是很耳熟?是的,你需要把processFile 的行为参数化。你需要一种方法把行为传递给 processFile ,以便它可以利用BufferedReader 执行不同的行为。
传递行为正是Lambda的拿手好戏。那要是想一次读两行,这个新的processFile 方法看起来又该是什么样的呢?基本上,你需要一个接收 BufferedReader 并返回 String 的Lambda。
String result = processFile((BufferedReader br) -> br.readLine()+br.readLine());
import java.io.BufferedReader;
import java.io.IOException;
@FunctionalInterface
public interface BufferedReaderProcessor {
String process(BufferedReader br) throws IOException;
}
//修改方法如下:
public static String processFile(BufferedReaderProcessor processor) throws IOException {}
public static String processFile(BufferedReaderProcessor processor) throws IOException {
try(BufferedReader br = new BufferedReader(new FileReader("data.txt"))){
return processor.process(br);
}
}
//处理一行
String result1 = processFile((BufferedReader br) -> br.readLine());
//处理二行
String result2 = processFile((BufferedReader br) -> br.readLine()+br.readLine());
下图总结了所采取的使 pocessFile 方法更灵活的四个步骤: