什么是 Lambda 表达式,我以为是咱们开始学习 Lambda 表达式以前应该要弄清楚的一个概念。咱们能够把 Lambda 表达式理解为简洁地表示能够传递的匿名函数的一种方式:它没有名称,但它有参数列表、函数主体、返回类型,可能还有一个能够抛出的异常列表。1
简单的说 Lambda 有如下的特色:
1.匿名,它没有一个明确的名字。
2.函数,是的, Lambda 表达式确实是一种函数,这毋庸置疑。
3.传递,Lambda 表达式能够做为参数传递给方法。
4.简洁,没有什么比 Lambda 更加简洁的语法了(Java 中)java
概念说完咱们就开始咱们的代码之旅——Lambda 的语法:
(paramenters) -> expression
或者
(paramenters) -> { statements; }
数据库
Lambda 参数
+ 箭头
+ Lambda 主体
构成。在 Java8 中 Lambda 表达式的体现形式有如下 5 中:
1.(String s) -> s.length()
这个 Lambda 表达式具备一个 String 类型的参数而且返回一个 Int。2express
2.(Apple a) -> a.getWeight() > 150
这个 Lambda 表达式具备一个 Apple 类型的参数而且返回一个 Boolean。多线程
3.(int x, int y) -> (System.out.println(x + y))
这个 Lambda 表达式具备一个 String 类型的参数然而它并无返回值(void 返回)。hexo
4.() -> 93
这个 Lambda 表达式没有参数,返回一个 Int。app
5.(Apple a, Apple b) -> a1.getWeight().compareTo(a2.getWeight())
最后一个 Lambda 表达式具备两个 Apple 类型的参数,返回一个 Int。函数
咱们刚刚已经了解了 Lambda 表达式的语法以及基本的 5 中表现形式,那么应该在哪里使用 Lambda 表达式以及如何使用 Lambda 表达式呢?通常咱们能够在函数式接口3上使用 Lambda 表达式。附录 A 列举了 JDK 8以前已有的函数式接口。学习
咱们最经常使用的应该是 java.lang.Runnable 接口了,在 Java8 以前要开启一个多线程,那么一定会写如下这段代码:flex
Runnable run = new Runnable(){ public void run(){ System.out.println("Start a new Thread"); } };
按照正常的缩进,咱们开启一个线程最少须要写 5 行代码,其中只有一行使咱们的主要核心,其余 4 行代码都是为之服务的,或者称之为样板式代码。有点像 JDBC 数据库链接池同样,先要建立链接对象...最后关闭链接池。而使用 Lambda 表达式能够有效的缩短代码的行数,而且让代码写的更加的清晰。线程
Runnable run = () -> System.out.println("Start a new Thread");
没错,就这么简单,一切显得是那么的优雅和华丽,没有什么多余的样板式代码,一眼就可以看代码的意图。不再用主动过滤掉无用的代码了,应为留下来的都是有用的代码。可能你一时还不习惯这样的方式或是写法,不要紧接着往下,会有更多的列子和惊喜。
刚刚咱们用函数式接口来使用 Lambda 表达式,还有一种方式是使用函数描述符——函数式接口的抽象方法基本上就是 Lambda 表达式的签名。就拿刚刚线程的代码来讲,Runnable 接口能够看作一个什么都没有返回的的函数签名,应为它只有一个 run 的抽象方法,这个方法既不接受参数也不返回参数。
public void process(Runnable r){ r.run(); } process(() -> System.out.println("Start a new Thread"));
废话很少说,先上代码:
public class ExecuteAround { public static void main(String ...args) throws IOException{ // method we want to refactor to make more flexible String result = processFileLimited(); System.out.println(result); System.out.println("---"); // 使用 Lambda 表达式改进 String oneLine = processFile((BufferedReader b) -> b.readLine()); System.out.println(oneLine); String twoLines = processFile((BufferedReader b) -> b.readLine() + b.readLine()); System.out.println(twoLines); } public static String processFileLimited() throws IOException { try (BufferedReader br = new BufferedReader(new FileReader("data.txt"))) { return br.readLine(); } } public static String processFile(BufferedReaderProcessor p) throws IOException { try(BufferedReader br = new BufferedReader(new FileReader("data.txt"))){ return p.process(br); } } public interface BufferedReaderProcessor{ public String process(BufferedReader b) throws IOException; } }
这个例子就是咱们平时处理资源的一段代码,咱们打开一个资源,作一些处理(读啊,写啊),而后关闭资源。这里对比了使用传统方式和使用 Lambda 表达式的方式来写这一段代码。这里能够看出使用 Lambda 表达式可使代码更加灵活,在这段代码中的提现是:能够由传入参数的不一样而决定方法的实现。
正如前面说的,函数式接口定义且只定义了一个抽象方法。咱们在 JDK8 以前经常使用的如 Comparable、Runnable 和 Callable 等,在 Java8 中伟大的设计师又引进了几个新的函数式接口,这里介绍其中的一些做为了解。
java.util.function.Predicate
@FunctionalInterface public interface Predicate<T>{ boolean test(T t); } public static List<Apple> filter(List<Apple> inventory, ApplePredicate p){ List<Apple> result = new ArrayList<>(); for(Apple apple : inventory){ if(p.test(apple)){ result.add(apple); } } return result; } List<Apple> greenApples = filter(inventory, (Apple a) -> "green".equals(a.getColor())); System.out.println(greenApples);
java.util.function.Consumer
@FunctionalInterface public interface Consumer<T>{ void accept(T t); } public static <T> forEach(List<T> list, Consumer<T> c){ for(T i: list){ c.accept(i); } } List<int> list = Arrays.asList(1, 2, 3, 4, 5); //Lambda 是 Consumer 中 accept 方法的实现 forEach(list, (Integer i) -> System.out.println(i))
java.util.function.Function<T, R> 接口定义了一个叫作 apply 的方法,该方法接受一个泛型的 T 对象,返回一个泛型的 R 对象。若是你须要一个 Lambda 表达式将对象的信息映射到输出,那么久可使用这个接口。
@FunctionalInterface public interface Function<T, R>{ R apply(T t); } public static <T, R> List<R> map(List<T> list, Function<T, R> f){ List<R> result = new ArrayList<>(); for(T s: list){ result.add(f.apply(s)); } return result; } List<int> list = Arrays.asList("java8", "in", "action"); List<Interger> listFun = map { list,(String s) -> s.length(); };
JDK 8以前已有的函数式接口:
java.lang.Runnable
java.util.concurrent.Callable
java.security.PrivilegedAction
java.util.Comparator
java.io.FileFilter
java.nio.file.PathMatcher
java.lang.reflect.InvocationHandler
java.beans.PropertyChangeListener
java.awt.event.ActionListener
javax.swing.event.ChangeListener
本文由我的 hexo 博客 co2fe.com 迁移
date: 2017-07-16 22:03:37