Java 8 Lambda

Posted Mr.袋鼠

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Java 8 Lambda相关的知识,希望对你有一定的参考价值。

最近查找资料学习时,发现例子中有好多地方用到了lambda表达式,所以今天学习记录一下。

推荐一个youtube的视频,讲解的非常不错。国内的伙伴有可能需要fan qiang才能看到。Good luck!!!

https://www.youtube.com/watch?v=gpIUfj3KaOc&list=PLqq-6Pq4lTTa9YGfyhyW2CqdtW9RtY-I3&index=1

 

Lambda表达式

它可以看做是函数型编程,那么java中函数定义就用接口来担当,所以,用到Lambda的时候需要使用一个接口。Lambda相关的语法规则也在下面代码中补充。

技术分享
 1 public class LamdbaDemo01 {
 2 
 3     public static void main(String[] args) {
 4 
 5         // new Thread( () -> System.out.println("--")).start();
 6         MyLambda greet = () -> System.out.println("Hello World!");
 7         greet.foo();
 8         // MyAdd myAdd = (int i, int j) -> i + j; 
 9         // 因为参数的变量名称一致,所以参数的变量类型可以省略
10         MyAdd myAdd = (i, j) -> i + j; 
11         System.out.println(myAdd.add(2, 3));
12         
13         // 当参数只有一个的时候可以省略() , 此外当箭头右侧的代码只用一行的时候,可以省略{}
14         MyLength myLength = s -> s.length();
15         System.out.println(myLength.leng("Hello world!"));
16     }
17 }
18 
19 // 接口中只能有一个方法,这是使用Lambda表达式的要求
20 interface MyLambda {
21     void foo();
22 }
23 
24 interface MyAdd {
25     int add(int i, int b);
26 }
27 
28 interface MyLength {
29     int leng(String s);
30 }
View Code

 

接下来看一个例子:

技术分享
1 public interface Condition {
2         boolean test (Person p);
3 }
View Code
技术分享
 1 import java.util.Arrays;
 2 import java.util.Collections;
 3 import java.util.Comparator;
 4 import java.util.List;
 5 
 6 public class Unit1ExercistWithJava7 {
 7 
 8     public static void main(String args[]) {
 9         
10     List<Person> list = Arrays.asList(
11             new Person ("Charles", "Dickens", 60),
12             new Person ("Lewis", "Carrol", 42),
13             new Person ("Thamos", "Cayloe", 51),
14             new Person ("Charlotte", "Brote", 45),
15             new Person ("Matthew", "Aroid", 39)
16             );
17     
18     // step 1: sort list by lastName
19     Collections.sort(list, new Comparator<Person>(){
20         @Override
21         public int compare(Person o1, Person o2) {
22             return o1.getLastName().compareTo(o2.getLastName());
23         }
24     } );
25     
26     // step 2: Create a method that print all elements in the list
27     printConditionally (list, new Condition(){
28         @Override
29         public boolean test(Person p) {
30             return true;
31         }
32     });
33     
34     System.out.println("-------------------------");
35     // step 3: Create a method that prints all people whose lastName beginning whie C
36     printConditionally(list, new Condition(){
37         @Override
38         public boolean test(Person p) {
39             return p.getLastName().startsWith("C");
40         }
41     });
42     }
43 
44     private static void printConditionally (List<Person> list, Condition condition) {
45         for (Person p : list) {
46             if (condition.test(p)) {
47                 System.out.println(p);
48             }
49         }
50     }
51 }
View Code

上面的例子很简单,就是创建一个接口,里面有test方法,之后创建了一个List,根据自己的需要将list中满足一定条件的值取出。这里例子是用Java7写的。

接下来看Lambda表达式的例子:

技术分享
 1 import java.util.Arrays;
 2 import java.util.Collections;
 3 import java.util.List;
 4 
 5 public class Unit1ExercistWithLambda {
 6 
 7     public static void main(String args[]) {
 8         
 9     List<Person> list = Arrays.asList(
10             new Person ("Charles", "Dickens", 60),
11             new Person ("Lewis", "Carrol", 42),
12             new Person ("Thamos", "Cayloe", 51),
13             new Person ("Charlotte", "Brote", 45),
14             new Person ("Matthew", "Aroid", 39)
15             );
16     
17     // step 1: sort list by lastName
18     // 使用Lambda表达式时,刚开始写不出,可以先写出匿名类的形式,之后在这个基础上再进行修改,慢慢的就会写了
19     // 为什么括号里直接省略掉参数类型,你尅看用Java8实现的例子
20     Collections.sort(list, (p1, p2) -> p1.getLastName().compareTo(p2.getLastName()));
21     
22     // step 2: Create a method that print all elements in the list
23     printConditionally (list, (p) -> true);
24     
25     System.out.println("-------------------------");
26     // step 3: Create a method that prints all people whose lastName beginning whie C
27     printConditionally(list, (p) -> p.getLastName().startsWith("C"));
28     }
29 
30     private static void printConditionally (List<Person> list, Condition condition) {
31         for (Person p : list) {
32             if (condition.test(p)) {
33                 System.out.println(p);
34             }
35         }
36     }
37 }
View Code

在这个例子中,条件判断的实现,通过Lambda表达式来实现,可以看到代码量的减少,这是它的一个好处。

我们现在思考一下使用Lambda表达式的步骤。首先需要有个接口,接口中,必须有且只有一个方法,这是使用Lambda的前提条件。

之后,你就可以编写接口的实现部分。

其实我们也可以不自己创建接口,使用java.util.function 包 里面存在的接口。

比如上面Lambda表达式的例子可以修改成如下:

技术分享
1 private static void printConditionally (List<Person> list, Predicate<Person> predict) {
2         for (Person p : list) {
3             if (predict.test(p)) {
4                 System.out.println(p);
5             }
6         }
7     }
View Code

这样的话,接口虽然修改了,但是Lambda实现的部分,完全不用任何修改,这是Lambda的另一个优势。

我们还在可以在printConditionally方法中再添加一个功能接口,例子如下:

技术分享
 1     // step 2: Create a method that print all elements in the list
 2     printConditionally (list, (p) -> true, (p) -> System.out.println(p));
 3     
 4     System.out.println("-------------------------");
 5     // step 3: Create a method that prints all people whose lastName beginning whie C
 6     printConditionally(list, (p) -> p.getLastName().startsWith("C"), (p) -> System.out.println(p));
 7     }
 8 
 9     private static void printConditionally (List<Person> list, Predicate<Person> predict, Consumer<Person> consumer) {
10         for (Person p : list) {
11             if (predict.test(p)) {
12                 consumer.accept(p);
13             }
14         }
15     }
View Code

个人感受是,Lambda表达式使代码解耦,提高结构的灵活性。

 

Exception的捕获

无例子不说话:

技术分享
 1 import java.util.function.BiConsumer;
 2 
 3 public class Unit1ExercistWithLambdaWithException {
 4 
 5     public static void main(String args[]) {
 6         int [] someNumbers = {1,2,3,4};
 7         int key = 0;
 8         /*第二种设想是在 process 方法中的第三个参数外侧添加try catch
 9         但是那样的话,跟java 7的匿名类有些相似,而且,又会增加耦合度。
10         最后,使用现在的,第三种方式来捕获异常。可能会觉得麻烦,跟之前的两种方法没什么区别,
11         但是第三种方式,我觉得有些像AOP,而且这样对结构的入侵要少*/
12         process (someNumbers, key, wrapperLambda((k ,v) -> System.out.println(k/v)));
13     }
14 
15     private static BiConsumer<Integer, Integer> wrapperLambda(BiConsumer<Integer, Integer> wrapper) {
16         return (k ,v) -> {
17             try {
18                 wrapper.accept(k, v);
19             } catch (ArithmeticException e) {
20                 System.out.println("Exception caught in wrapper lambda");
21             }
22         };
23     }
24 
25     private static void process(int[] someNumbers, int key, BiConsumer<Integer, Integer> consumer) {
26         // Exception的捕捉的第一种设想是在下面代码块的外侧追加try catch 来捕捉异常
27         // 但是,这只是个抽象的process的方法,不能确定实现类中出现的异常,所以在这里捕捉,不合理
28         for (int i : someNumbers) {
29             consumer.accept(i, key);
30         }
31     }
32 }
View Code

不知道怎么该如何讲述这个部分,例子有注释,大家不懂的地方,再留言谈论。

 

方法的引用

例子如下:

技术分享
 1 public class MethodReference {
 2 
 3     public static void main(String[] args) {
 4 
 5         // 下面两行的代码是等价的
 6         // Thread thread = new Thread(() -> printMessage());
 7         Thread thread = new Thread(MethodReference::printMessage);
 8         thread.start();
 9     }
10 
11     private static void printMessage() {
12         System.out.println("Hello World!");
13     }
14 
15 }
View Code

 Unit1ExercistWithLambda3.java 中的例子中的部分代码:

技术分享
1 // printConditionally(list, (p) -> p.getLastName().startsWith("C"), (p) -> System.out.println(p));
2     
3     printConditionally(list, (p) -> p.getLastName().startsWith("C"), System.out::println);
View Code

 

foreach

技术分享
 1 import java.util.Arrays;
 2 import java.util.List;
 3 
 4 public class CollectionIterationExample {
 5 
 6     public static void main(String[] args) {
 7         List<Person> list = Arrays.asList(
 8                 new Person ("Charles", "Dickens", 60),
 9                 new Person ("Lewis", "Carrol", 42),
10                 new Person ("Thamos", "Cayloe", 51),
11                 new Person ("Charlotte", "Brote", 45),
12                 new Person ("Matthew", "Aroid", 39)
13                 );
14         
15         System.out.println("Using for loop");
16         for (int i=0; i<list.size();i++) {
17             System.out.println(list.get(i));
18         }
19         
20         System.out.println("Using for each loop");
21         for (Person person : list) {
22             System.out.println(person);
23         }
24         
25         // Java8 Lambda
26         System.out.println("Using for loop");
27         list.forEach(p -> System.out.println(p));
28         System.out.println("--------------");
29         list.forEach(System.out::println);
30     }
31 
32 }
View Code

 

觉得Lambda的表达式非常便捷。

以上是关于Java 8 Lambda的主要内容,如果未能解决你的问题,请参考以下文章

聊聊Java 8的Lambda表达式和函数式接口

Java 8 lambda表达式20180404

Java 8 lambda表达式示例

《On Java 8》中文版 第十三章 函数式编程

Java--8--新特性--Lambda

Java 8 新特性