公子奇带你一步一步了解Java8中Lambda表达式

上一篇《公子奇带你一步一步了解Java8中行为参数化》中,咱们演示到最后将匿名实现简写为html

1 (Police police) -> "浙江".equals(police.getPoliceNativePlace());

这是一个带有箭头的函数,这种写法在Java8中即为Lambda表达式。那么咱们就来好好的讲讲Lambda表达式。java

一 、什么是Lambda表达式

首先咱们须要知道Lambda表达式时JDK8中提出的编码风格,它能够简洁地表示可做为参数传递的匿名函数的一种方式,也能够理解为匿名实现的一种,关于匿名对象的特征它也是有的,例如:它没有名称,但它有参数列表、函数主体、返回类型,可能还有一个能够抛出的异常列表。基本语法可使用如下两种方式表示:express

1 (parameters) -> expression 
2 3 (parameters) -> { statements; }

由上可知Lambda表达式有三个部分:app

一、参数列表ide

二、箭头 “ -> ” 用来将参数和主体链接到一块儿函数

三、Lambda主体ui

如下咱们经过一些案例来表示一个有效的Lambda表达式编码

1 () -> "ABC";  //没有参数但有返回值ABC,return 关键字自动忽略
2 () -> {};     //没有参数,方法体不执行任何操做
3 () -> {return "ABC"}; //没有参数,返回ABC,有大括号,须要显示return
4 (String s) -> s.length(); //有一个参数,并对参数进行操做
5 (int x, int y) -> {       //有两个参数,并作复杂操做,须要大括号
6     System.out.println("result:");
7     System.out.println(x + y);
8 }
9 (String s1, String s2) -> s1.compareTo(s2) //对两个参数操做

2、什么是函数式接口

上一篇文章中,咱们最后的Lambda表达式是做为一个参数传递给filter方法的,同时在filter方法中的第二个参数是一个接口Predicate<T>,这个接口在JDK8中咱们就将其称为函数式接口,回看这个接口只有一个抽象方法。即函数式接口就是只定义一个抽象方法的接口。同时在JDK8中也使用了注解 @FunctionInterface 将一个接口标注为函数式接口,固然没有添加该注解也可为函数式接口,只是添加后程序在运行时会进行检测,不然会抛出异常。同时为了实现更灵活的操做,接口中能够添加静态方法和默认方法(即JDK8以后,接口中是能够定义方法实现的)。spa

 1 package com.hz;
 2 
 3 /**
 4  * 在1.8以前,咱们一直强调接口中不可有方法实现
 5  * 1.8以后是能够在接口中定义默认方法和静态方法
 6  */
 7 public interface InterfaceMethod {
 8 
 9     default void method1() {
10         System.out.println("接口的默认方法实现...");
11     }
12 
13     static void method2() {
14         System.out.println("接口的静态方法实现...");
15     }
16 
17     public static void main(String[] args) {
18         InterfaceMethod.method2();
19 
20         new InterfaceMethod() {}.method1();
21     }
22 }
23 
24 //官方提供的一个函数式接口
25 package java.util.function;
26 
27 import java.util.Objects;
28 
29 @FunctionalInterface
30 public interface Predicate<T> {
31     boolean test(T t);
32 
33     default Predicate<T> and(Predicate<? super T> other) {
34         Objects.requireNonNull(other);
35         return (t) -> test(t) && other.test(t);
36     }
37 
38     default Predicate<T> negate() {
39         return (t) -> !test(t);
40     }
41 
42     default Predicate<T> or(Predicate<? super T> other) {
43         Objects.requireNonNull(other);
44         return (t) -> test(t) || other.test(t);
45     }
46 
47     static <T> Predicate<T> isEqual(Object targetRef) {
48         return (null == targetRef)
49                 ? Objects::isNull
50                 : object -> targetRef.equals(object);
51     }
52 }
53 
54 //说明:从官网的Predicate接口中咱们能够发现除了多了注解和一些方法实现,与咱们上一讲本身定义的Predicate接口很相似

3、为何提出函数式接口

    可能到这里你也发现了,既然Lambda表达式已经很简洁的表达了实现,咱们为何还须要引入函数式接口的概念呢?为了简化代码和灵活运用,咱们提出了Lambda表达式的概念,Lambda表达式容许你直接之内联的形式为函数式接口的抽象方法提供实现,并把整个表达式做为函数式接口的实例。由此便可理解:Lambda表达式是函数式接口的一种实现。code

    在JDK8中咱们会发现大部分函数式接口都添加了 @FunctionInterface 注解,但咱们不能仅仅理解为只有添加了该注解的才为函数式接口,咱们应该理解的是只有一个抽象方法的接口才为函数式接口。

4、应用场景

    既然Lambda表达式这么好,那么咱们应该在哪里去使用呢?下面介绍一些经常使用的:

    一、列表循环操做

 1 package com.hz;
 2 
 3 import java.util.Arrays;
 4 import java.util.List;
 5 import java.util.function.Consumer;
 6 
 7 public class LambdaTest {
 8     public static void main(String[] args) {
 9         List<String> ss = Arrays.asList("gong", "zi", "qi", "666");
10 
11         //打印列表中每一个值长度
12         //---匿名实现
13         ss.forEach(new Consumer<String>() {
14             @Override
15             public void accept(String s) {
16                 System.out.println(s.length());
17             }
18         });
19         
20         System.out.println("------------------");
21         
22         //--遍历取值
23         for (String s : ss) {
24             System.out.println(s.length());
25         }
26 
27         System.out.println("---------");
28 
29         //--Lambda表达式
30         ss.forEach((String s) -> System.out.println(s.length()));
31     }
32 }
33 //哪一种方式简洁、容易理解很明显

    二、事件监听

 1 //监听实现一
 2 Button button = new Button("提交");
 3 button.addActionListener(new ActionListener() {
 4     @Override
 5     public void actionPerformed(ActionEvent e) {
 6         System.out.println("用户点击了提交按钮");
 7     }
 8 });
 9 
10 //监听实现二
11 button.addActionListener(e -> {
12     System.out.println("用户点击了提交按钮");
13 });

    三、函数式接口(回看上一篇文章)

    更多应用场景,咱们在后续文章中再整理。

5、引出方法引用

    咱们继续回看上一篇,发如今最后调用表达式是何其的类似

1 Police police) -> police.getPoliceAge() > 30;
2 
3 System.out.println("---------------");
4 
5 (Police police) -> "浙江".equals(police.getPoliceNativePlace());

    那么在JDK8中还能够再次简化吗?答案是确定的,这就是方法引用。即

1 Police :: getPoliceAge;
2 String :: equals;

    方法引用的加入可让咱们重复使用现有的方法定义,并像Lambda同样传递它们。咱们同时可理解为方法引用是针对仅仅涉及单一方法的Lambda的语法糖。

    那么什么状况下,咱们能够及如何构建方法引用?

      一、指向静态方法的方法引用。

      二、指向任意类型实例方法的方法引用。

      三、指向现有对象的实例方法的方法引用。

6、复合Lambda表达式组装

    在实际开发中,咱们不可能只操做一种或一个Lambda表达式,一个表达式的输出可能会是另外一个表达式的输入,两个条件的同时知足(例如上一篇中籍贯为浙江年龄大于30的民警),或多个条件只要有一个合适即命中(例如上一篇中籍贯为浙江或年龄大于30的民警)等。如此咱们将其分为3类。

    一、比较器复合

继续回到上一篇文章,如何对民警年龄进行排列。

 1 public static void main(String[] args) {
 2     List<Police> polices = Arrays.asList(new Police("P001", "余警官", 27, "浙江"),
 3             new Police("P002", "李警官", 32, "安徽"),
 4             new Police("P003", "程警官", 25, "安徽"),
 5             new Police("P004", "杨警官", 35, "浙江"),
 6             new Police("P005", "杨警官", 31, "上海"));
 7 
 8     polices.sort(comparing(Police :: getPoliceAge).reversed());
 9 
10     System.out.println("结果1: " + polices);
11 }

    二、谓词复合

1 Predicate<Police> p = (Police police) -> police.getPoliceAge() > 30;
2 Predicate<Police> p2 = p.and((Police police) -> "浙江".equals(police.getPoliceNativePlace()));
3 List<Police> result = filter(polices, p2);
4 System.out.println(result);
5 
6 //固然 除了 and  还有 or方法

    三、函数复合

1 Function<Integer, Integer> f = x -> x + 1;
2 Function<Integer, Integer> g = x -> x * 2;
3 Function<Integer, Integer> h = f.andThen(g);
4 int result = h.apply(1);
5 System.out.println(result);

7、一个实例

    回到上一篇文章场景,将按照必定条件获得的民警按照年龄、籍贯排序。

 1 package com.hz;
 2  
 3 import java.util.ArrayList;
 4 import java.util.Arrays;
 5 import java.util.List;
 6 import java.util.function.Predicate;
 7 
 8 import static java.util.Comparator.comparing;
 9 
10 public class PoliceMain {
11     public static void main(String[] args) {
12         List<Police> polices = Arrays.asList(new Police("P001", "余警官", 27, "浙江"),
13                 new Police("P002", "李警官", 32, "安徽"),
14                 new Police("P003", "程警官", 25, "安徽"),
15                 new Police("P004", "杨警官", 35, "浙江"),
16                 new Police("P005", "张警官", 31, "上海"),
17                 new Police("P006", "王警官", 42, "浙江"),
18                 new Police("P007", "赵警官", 31, "浙江"),
19                 new Police("P008", "刘警官", 49, "浙江"),
20                 new Police("P009", "周警官", 32, "浙江"));
21 
22         //问题:找出籍贯为浙江而且年龄大于30岁的民警或者籍贯为安徽的民警,按照民警年龄排序,若年龄相同按照籍贯排序
23         Predicate<Police> p1 = (Police police) -> police.getPoliceAge() > 30;
24 
25         Predicate<Police> p2 = p1.and((Police police) -> "浙江".equals(police.getPoliceNativePlace()));
26 
27         Predicate<Police> p3 = p2.or((Police police) -> "安徽".equals(police.getPoliceNativePlace()));
28 
29         List<Police> result = filter(polices, p3);
30 
31         result.sort(comparing(Police :: getPoliceAge).thenComparing(Police :: getPoliceNativePlace));
32 
33         System.out.println("结果: " + result);
34     }
35 
36     static <T> List<T> filter(List<T> con, Predicate<T> p) {
37         List<T> result = new ArrayList<>();
38 
39         for (T e : con) {
40             if (p.test(e)) {
41                 result.add(e);
42             }
43         }
44 
45         return result;
46     }
47 
48 }
49 
50 // 以上方式须要咱们本身去定义一个filter方法  或按照如下方式
51 
52 package com.hz;
53 
54 import java.util.ArrayList;
55 import java.util.Arrays;
56 import java.util.List;
57 import java.util.function.Function;
58 import java.util.function.Predicate;
59 
60 import static java.util.Comparator.comparing;
61 
62 public class PoliceMain {
63     public static void main(String[] args) {
64         List<Police> polices = Arrays.asList(new Police("P001", "余警官", 27, "浙江"),
65                 new Police("P002", "李警官", 32, "安徽"),
66                 new Police("P003", "程警官", 25, "安徽"),
67                 new Police("P004", "杨警官", 35, "浙江"),
68                 new Police("P005", "张警官", 31, "上海"),
69                 new Police("P006", "王警官", 42, "浙江"),
70                 new Police("P007", "赵警官", 31, "浙江"),
71                 new Police("P008", "刘警官", 49, "浙江"),
72                 new Police("P009", "周警官", 32, "浙江"));
73 
74         //问题:找出籍贯为浙江而且年龄大于30岁的民警或者籍贯为安徽的民警,按照民警年龄排序,若年龄相同按照籍贯排序
75         Predicate<Police> p1 = (Police police) -> police.getPoliceAge() > 30;
76 
77         Predicate<Police> p2 = p1.and((Police police) -> "浙江".equals(police.getPoliceNativePlace()));
78 
79         Predicate<Police> p3 = p2.or((Police police) -> "安徽".equals(police.getPoliceNativePlace()));
80 
81         Function<List<Police>, List<Police>> f = (List<Police> list) -> {
82             List<Police> temp = new ArrayList<>();
83             for (Police police : list) {
84                 if (p3.test(police)) {
85                     temp.add(police);
86                 }
87             }
88             return temp;
89         };
90 
91         List<Police> result = f.apply(polices);
92 
93         result.sort(comparing(Police :: getPoliceAge).thenComparing(Police :: getPoliceNativePlace));
94 
95         System.out.println("结果: " + result);
96     }
97 
98 }
相关文章
相关标签/搜索