Lambda表达式理解为简洁地表示可传递的匿名函数的一种方式:它没有名称,但它
有参数列表、函数主体、返回类型,可能还有一个可以抛出的异常列表。
在函数式接口上使用Lambda表达式。 函数式接口就是只定义一个抽象方法的接口。
函数式接口举例:
public interface Comparator<T> { int compare(T o1, T o2); } public interface Runnable{ void run(); } public interface Predicate<T>{ boolean test (T t); }
Lambda应用举例:
List<Apple> greenApples = filter(inventory, (Apple a) -> "green".equals(a.getColor()));
在上面的代码中,把 Lambda 表达式作为第二个参数传给 filter 方法,因为它这里需要
Predicate,而这是一个函数式接口。
函数式接口的抽象方法的签名基本上就是Lambda表达式的签名。
凡是使用函数式接口的地方都可以使用Lambda表达式
例如:
() -> void,代表参数列表为空,返回void的函数。这正是Runnable所代表的。
(Apple, Apple) -> int,代表接收两个Apple作为参数且返回int的函数。
通过一个例子,看看在实践中如何利用Lambda和行为参数化来让代码更为灵活,更为简洁。
原始方法如下:
缺点是只能读文件的第一行。如果你想要返回头两行,甚至是返回使用最频繁的词,怎么办?复制、粘贴,修改有用工作的那行代码?
第1步:行为参数化
你需要一种方法把行为传递给processFile
String result = processFile(“行为”);
第2步:使用函数式接口传递行为
// 定义函数式接口 @FunctionalInterface public interface BufferedReaderProcessor { String process(BufferedReader b) throws IOException; } // 把这个接口作为新的processFile方法的参数 public static String processFile(BufferedReaderProcessor p) throws IOException { … }
第3步:执行行为
public static String processFile(BufferedReaderProcessor p) throws IOException { try (BufferedReader br = new BufferedReader(new FileReader("data.txt"))) { return p.process(br); // 执行行为 } }
第4步:传递Lambda
// 处理一行 String oneLine = processFile((BufferedReader br) -> br.readLine()); // 处理两行 String twoLines = processFile((BufferedReader br) -> br.readLine() + br.readLine());
Java 8的库设计师帮你在java.util.function包中引入了几个新的函数式接口。
总结如下:
1. Predicate
java.util.function.Predicate<T>接口定义了一个名叫test的抽象方法,它接受泛型T对象,并返回一个boolean。
2. Consumer
java.util.function.Consumer<T>定义了一个名叫accept的抽象方法,它接受泛型T的对象,没有返回(void)。
@FunctionalInterface public interface Consumer<T>{ void accept(T t); } public static <T> void forEach(List<T> list, Consumer<T> c){ for(T i: list){ c.accept(i); } } // 调用举例 forEach(Arrays.asList(1,2,3,4,5), (Integer i) -> System.out.println(i));
3.Function
java.util.function.Function<T, R>接口定义了一个叫作apply的方法,它接受一个泛型T的对象,并返回一个泛型R的对象