Lambda
https://www.cnblogs.com/qdhxhz/p/9393724.html
https://blog.csdn.net/qq_21583077/article/details/88706645
https://www.jb51.net/article/160005.htm
https://mp.weixin.qq.com/s/TjetWEvJsSbJ9N-51ECkbw
1、什么是Lambda表达式
Lambda 表达式是一种匿名函数,简单地说,它是没有声明的方法,也即没有访问修饰符、返回值声明和名字。
它可以写出更简洁、更灵活的代码。作为一种更紧凑的代码风格,使 Java 语言的表达能力得到了提升。
2、Lambda表达式的语法
基本语法: (parameters) -> expression
或者:(parameters) ->{ statements;
举例说明:
// 1. 不需要参数,返回值为 5 () -> 5 // 2. 接收一个参数(数字类型),返回其2倍的值 x -> 2 * x // 3. 接受2个参数(数字),并返回他们的差值 (x, y) -> x – y // 4. 接收2个int型整数,返回他们的和 (int x, int y) -> x + y // 5. 接受一个 string 对象,并在控制台打印,不返回任何值(看起来像是返回void) (String s) -> System.out.print(s)
3、什么是函数式接口
再对上面进行举例说明之前,必须先来理解下函数式接口,因为Lambda是建立在函数式接口的基础上的。
记住!
(1)只包含一个抽象方法的接口,称为函数式接口。
(2)你可以通过 Lambda 表达式来创建该接口的对象。
(3)我们可以在任意函数式接口上使用 @FunctionalInterface 注解,这样做可以检测它是否是一个函数式接口,同时 javadoc 也会包含一条声明,说明这个接口是一个函数式接口。
在实际开发者有两个比较常见的函数式接口:Runnable接口,Comparator接口
public class Test { public static void main(String[] args) { // 1.1使用匿名内部类 new Thread(new Runnable() { @Override public void run() { System.out.println("Hello world !"); } }).start(); // 1.2使用 lambda 获得Runnable接口对象 new Thread(() -> System.out.println("Hello world !")).start(); //============================================================================= // 2.1使用匿名内部类 Runnable race1 = new Runnable() { @Override public void run() { System.out.println("Hello world !"); } }; // 2.2使用 lambda直接获得接口对象 Runnable race2 = () -> System.out.println("Hello world !"); // 直接调用 run 方法(没开新线程哦!) race1.run(); race2.run(); } } /*输出结果 * Hello world ! * Hello world ! * Hello world ! * Hello world ! */
通过上面案例可以看出:通过Lambda表达式看去舒服清爽多了,而通过匿名内部类代码总是不够整洁。
再举一个例子:使用Lambda对数组排序
public class TestArray { public static void main(String[] args) { String[] players = {"zhansgan", "lisi", "wangwu", "zhaoliu", "wangmazi"}; // 1.1 使用匿名内部类根据 surname 排序 players Arrays.sort(players, new Comparator<String>() { @Override public int compare(String s1, String s2) { return (s1.compareTo(s2)); } }); // 1.2 使用 lambda 排序,根据 surname Arrays.sort(players, (String s1, String s2) -> s1.compareTo(s2)); //================================================================================================ // 2.1 使用匿名内部类根据 name lenght 排序 players Arrays.sort(players, new Comparator<String>() { @Override public int compare(String s1, String s2) { return (s1.length() - s2.length()); } }); // 2.2使用Lambda,根据name length Arrays.sort(players, (String s1, String s2) -> (s1.length() - s2.length())); //================================================================================================== // 3.1 使用匿名内部类排序 players, 根据最后一个字母 Arrays.sort(players, new Comparator<String>() { @Override public int compare(String s1, String s2) { return (s1.charAt(s1.length() - 1) - s2.charAt(s2.length() - 1)); } }); // 3.2 使用Lambda,根据最后一个字母 Arrays.sort(players, (String s1, String s2) -> (s1.charAt(s1.length() - 1) - s2.charAt(s2.length() - 1))); } }
通过上面例子我们再来思考为什么Lambda表达式需要函数式接口?其实很简单目的就是为来保证唯一。
你的Runnable接口只要一个抽象方法,那么我用() -> System.out.println("Hello world !"),就只能代表run方法,如果你下面还有一个抽象方法,那我使用Lambda表达式,那鬼才知道要调用哪个抽象方法呢。
Lambda表达式允许你通过表达式来代替功能接口。 lambda表达式就和方法一样,它提供了一个正常的参数列表和一个使用这些参数的主体(body,可以是一个表达式或一个代码块)。Lambda表达式还增强了集合库。 Java SE 8添加了2个对集合数据进行批量操作的包: java.util.function 包以及java.util.stream 包。
流(stream)就如同迭代器(iterator),但附加了许多额外的功能。 总的来说,lambda表达式和 stream 是自Java语言添加泛型(Generics)和注解(annotation)以来最大的变化。 我们先从最简单的示例来介绍Lambda表达式。
①用Lambda表达式实现Runnable:
@Test public void test1(){ //使用Java8之前 new Thread(new Runnable() { @Override public void run() { System.out.println("使用Lambda表达式之前,需要这么写!"); } }).start(); //使用Lambda表达式 new Thread(() -> System.out.println("使用Lambda表达式,只需要这一句话!")).start(); }
②使用Lambda表达式进行事件处理:
。。。。。
Lambda结合FunctionalInterface Lib, forEach, stream(),method reference等新特性可以使代码变的更加简洁!
利用函数式接口包
用Iterable.forEach()取代foreach loop
利用stream()替代静态函数
如果是println(p),则可以利用Method reference代替forEach中的Lambda表达式
Lambda配合Optional可以使Java对于null的处理变的异常优雅
我们现在就来对比一下下面四种常见的null处理中,Java 8的Lambda+Optional和传统Java两者之间对于null的处理差异。