Java8新特性(Lambda表达式、Stream流、Optional类)等

1. Lambda表达式由来

 1 package java8;
 2 
 3 public class EmployeeTest {
 4     public static void main(String[] args) {
 5 
 6         Employee employee1 = new EmployeeImpl();
 7         employee1.getSalary();
 8         System.out.println("****************");
 9 
10 
11         Employee employee2 = new Employee() {
12             @Override
13             public void getSalary() {
14                 System.out.println("Employee匿名内部类");
15             }
16         };
17         employee2.getSalary();
18         System.out.println("****************");
19 
20         /**
21          * lambda表达式可以看作是一个接口的实例,使用lambda是有前提条件的,就是该接口必须是函数式接口。
22          * 那么什么是函数式接口呢?用一句话总结就是有且仅有一个抽象方法的接口(在java提供的类库中,函数式接口上面都有@FunctionalInterface注解)
23          *
24          * lambda表达式可以总结为:一个(), 一个 ->, 一段代码{}
25          * 一个():参数
26          * 一段代码{}:具体业务逻辑
27          */
28         Employee employee3 = () -> {
29             System.out.println("将上述匿名内部类转为使用lambda表达式");
30         };
31         employee3.getSalary();
32     }
33 
34     interface Employee {
35         public void getSalary();
36     }
37 
38     static class EmployeeImpl implements Employee {
39 
40         @Override
41         public void getSalary() {
42             System.out.print("Employee的普通实现类");
43         }
44     }
45 }

 

2. Stream流

2.1 函数型接口Function定义

 1 package java8;
 2 
 3 import java.util.function.Function;
 4 
 5 /**
 6  * 1. 函数型接口Function<T,R>:有输入,有输出
 7  * 核心抽象方法为 抽象方法 R apply(T t);
 8  */
 9 public class FunctionInterface1 {
10 
11     public static void main(String[] args) {
12         // 通过lambda实例化一个接口,实现抽象方法R apply(T t);
13         Function<String, Integer> function = (s) -> {
14             if (s == null) {
15                 return 0;
16             }
17             return s.length();
18         };
19         Integer result = testFunction("hello", function);
20         System.out.println(result);
21 
22         System.out.println("****************");
23         System.out.println(testFunction("hello", s -> {
24             return "更简化的写法".length();
25         }));
26     }
27 
28 
29     // interface Function<T, R> 抽象方法 R apply(T t);
30     private static Integer testFunction(String str, Function<String, Integer> function) {
31         // str作为第13行的参数s进行传递
32         return function.apply(str);
33     }
34 }

 结果

5
****************
6

2.1 函数型接口Function类型

    • 函数型接口Function<T,R>
      • 抽象方法 R apply(T t)
    • 消费型接口Consumer<T>
      •  抽象方法:void accept(T t)
    • 供给型接口Supplier<T>
      •  抽象方法:T get()
    • 断言型接口Predicate<T>
      •  抽象方法:boolean test(T t)
 1 package java8;
 2 
 3 import java.util.function.Function;
 4 
 5 /**
 6  * 1. 函数型接口Function<T,R>:有输入,有输出
 7  * 核心抽象方法为 抽象方法 R apply(T t);
 8  */
 9 public class FunctionInterface1 {
10 
11     public static void main(String[] args) {
12         // 通过lambda实例化一个接口,实现抽象方法R apply(T t);
13         Function<String, Integer> function = (s) -> {
14             if (s == null) {
15                 return 0;
16             }
17             return s.length();
18         };
19         Integer result = testFunction("hello", function);
20         System.out.println(result);
21 
22         System.out.println("****************");
23         System.out.println(testFunction("hello", s -> {
24             return "更简化的写法".length();
25         }));
26     }
27 
28 
29     // interface Function<T, R> 抽象方法 R apply(T t);
30     private static Integer testFunction(String str, Function<String, Integer> function) {
31         // str作为第13行的参数s进行传递
32         return function.apply(str);
33     }
34 }

 

 1 package java8;
 2 
 3 import java.util.function.Consumer;
 4 
 5 /**
 6  * Consumer<T> 消费性接口有输入,但是没有返回值
 7  *     抽象方法:void accept(T t);
 8  */
 9 public class ConsuerFunctionInterface {
10 
11     public static void main(String[] args) {
12         // s是实例化方法accept的参数,{}内部是accept的方法体
13         testConsumer(s -> {System.out.println(s);}, "消费性接口抽象方法accept实现");
14     }
15 
16     private static void testConsumer(Consumer<String> consumer, String str) {
17         consumer.accept(str);
18     }
19 }

 

 1 package java8;
 2 
 3 
 4 import java.util.function.Supplier;
 5 
 6 /**
 7  * Supplier<T> 供给型接口:无输入、有输出
 8  *     抽象方法:T get();
 9  */
10 public class SupplierFunctionInterface {
11 
12     public static void main(String[] args) {
13 
14         // ()是实例化方法T get()参数:即无参数,{}是get的方法体
15         testSupplier(()-> {
16             String name = "Supplier<Person>的抽象方法get实现";
17             System.out.println(name);
18             return new Person(name);
19         });
20     }
21 
22     private static Person testSupplier(Supplier<Person> supplier) {
23         return supplier.get();
24     }
25 
26 }
27 
28 class Person {
29     private static String name;
30 
31     Person(String name) {
32         this.name = name;
33     }
34 }

 

 1 package java8;
 2 
 3 import java.util.function.Predicate;
 4 
 5 /**
 6  * 断言型接口Predicate<T>
 7  *     抽象方法:boolean test(T t);
 8  */
 9 public class PredicateFunctionInterface {
10 
11     public static void main(String[] args) {
12         // b是test方法的参数, {}内部是test方法体
13         boolean res = testPredicate((b) -> {
14             System.out.println("断言型接口Predicate抽象方法boolean test(T t)的实例化");
15             return b > 99;
16         }, 99);
17 
18         System.out.println("b>99, res=" + res);
19     }
20 
21 
22     private static boolean testPredicate(Predicate<Integer> predicate, int a) {
23         return predicate.test(a);
24     }
25 }

2.3 reduce

https://www.cnblogs.com/flydean/p/java-8-stream-reduce.html

https://www.liaoxuefeng.com/wiki/1252599548343744/1322402971648033

https://blog.csdn.net/qq_33351091/article/details/82494855

 1 package mtee3rule;
 2 
 3 import java.util.Arrays;
 4 import java.util.List;
 5 import java.util.Optional;
 6 
 7 public class ReduceTest {
 8 
 9     public static void main(String[] args) {
10         List<Integer> intList = Arrays.asList(1,2,3,4);
11 
12         Optional<Integer> result1 = intList.stream().reduce(Integer::sum);
13         System.out.println("result1=" + result1 + ", sum=" + result1.get());
14 
15         Integer result2=intList.stream().reduce(100, Integer::sum);
16         System.out.println("result2=" + result2 + ", sum=" + result2);
17 
18         // 每个线程的初始累加值都是100,最后4个线程加出来的结果就是406
19         // 这里sum方法的identity只能是0。所以这里我们传入100是不对的,因为sum(100+1)!= 1。
20         // 如果我们用0作为identity,则stream和parallelStream计算出的结果是一样的。这就是identity的真正意图。
21         Integer result3=intList.parallelStream().reduce(100, Integer::sum);
22         System.out.println("result3=" + result2 + ", sum=" + result3);
23 
24         testMultiReduce1();
25     }
26 
27     private static void testMultiReduce1() {
28         List<String> strings = Arrays.asList("1", "2", "4", "5");
29 
30         System.out.println("********in testMultiReduce1()************");
31 
32         // 非并行流
33         Integer reduce1 = strings.stream().reduce(0,
34                 (acc, e) -> acc + Integer.valueOf(e), (u, t) -> {
35                     // 非并行流,不会执行第三个参数
36                     System.out.println("u----:" + u);
37                     // 这里的返回值并没有影响返回结果
38                     return null;
39                 });
40         System.out.println("reduce1:" + reduce1);
41 
42         // 并行流
43         //System.out.println("out_thread=" + Thread.currentThread().getName());
44         Integer reduce2 = strings.parallelStream().reduce(0,
45                 (acc, e) -> acc + Integer.valueOf(e), (u, t) -> {
46                     // u,t分别为并行流每个子任务的结果
47                     System.out.println("inner_thread=" + Thread.currentThread().getName() + ", u=" + u + ", t=" + t);
48 
49                     return u + t;
50                 });
51         System.out.println("out_thread=" + Thread.currentThread().getName());
52         System.out.println("reduce2:" + reduce2);
53     }
54 
55 }

 

结果:

 1 result1=Optional[10], sum=10
 2 result2=110, sum=110
 3 result3=110, sum=410
 4 ********in testMultiReduce1()************
 5 reduce1:12
 6 inner_thread=ForkJoinPool.commonPool-worker-2, u=1, t=2    // 第一个线程执行
 7 inner_thread=main, u=4, t=5                                // 第二个线程执行
 8 inner_thread=main, u=3, t=9                                // u为第6行执行结果3,t为第7行执行结果9
 9 out_thread=main
10 reduce2:12                                                 // 第8行执行结果 = 3 + 9

 

2.4 创建Stream流的方式

 2.4.1 ::(双冒号)使用

https://www.jianshu.com/p/96b4815d629e

 1 package java8;
 2 
 3 import java.util.Arrays;
 4 import java.util.Comparator;
 5 import java.util.List;
 6 import java.util.Optional;
 7 
 8 public class DoubleMaoHao {
 9 
10     public static void main(String[] args) {
11         List<String> listStr = Arrays.asList("adnm", "p", "admmt", "pot", "xbangd", "weoujgsd");
12 
13         // 最大的串:实例化Comparator的抽象方法int compare(T o1, T o2)
14         // (o1, o2)有两个参数,o1作为当前对象,o2作为参数,都是String;返回值为int —— 其它方法满足这样条件的也可以
15         Optional<String> optionalMax1 = listStr.stream().max(((o1, o2) -> { return o1.compareTo(o2);} ));
16 
17         // 简写
18         // 而String::compareTo方法是指int compareTo(String anotherString)--即参数为string,返回值为int的
19         // 其它方法 public int indexOf(String str) --即参数为string,返回值为int的 也可以,但是int length() 无参数的方法就不行
20         Optional<String> optionalMax2 = listStr.stream().max(String::compareTo);  // String::length报错
21 
22         System.out.println("optionalMax1=" + optionalMax1.get() + ", optionalMax2=" + optionalMax2.get());  // optionalMax3=adnm, optionalMax4=w3
23 
24 
25         List<String> listStr3 = Arrays.asList("adnm", "dn", "n");
26         List<String> listStr4 = Arrays.asList("adnm", "w3", "3");
27         Optional<String> optionalMax3 = listStr3.stream().max(String::indexOf);  // adnm.indexOf("dn")>0, "dn".indexOf("n")>0
28         Optional<String> optionalMax4 = listStr4.stream().max(String::indexOf); // adnm.indexOf("w3")<0, "w3".indexOf("3")>0
29         System.out.println("optionalMax3=" + optionalMax3.get() + ", optionalMax4=" + optionalMax4.get());  // optionalMax3=adnm, optionalMax4=w3
30 
31         Optional<String> optionalMax5 = listStr.stream().max((o1,o2) -> {return 1;});  // >=0:adnm 即两两比较 前面最大; <0,则最后一个最大
32         System.out.println("optionalMax5=" + optionalMax5.get());  // max=adnm (第0个)
33 
34         Optional<String> optionalMax6 = listStr.stream().max((o1,o2) -> {return -1;});  // >=0:adnm 即两两比较 前面最大; <0,则最后一个最大
35         System.out.println("optionalMax6=" + optionalMax6.get());  // max=weoujgsd (最后一个)
36 
37 
38         /**
39          * max()方法中需要一个函数式接口Comparator<T>
40          * comparing方法中需要一个函数型接口Function<T, R>,唯一的抽象方法为R apply(T t);
41          * x作为Function方法的参数,到了Function方法体里 x作为对象来调用 无参数方法(这里x是String类型,则可以调用String的所有无参方法且返回值为int)
42          */
43         Optional<String> max1 = listStr.stream().max(Comparator.comparing((x) -> {
44             return x.length();
45         }));
46         Optional<String> max2 = listStr.stream().max(Comparator.comparing((x) -> {
47             return 1;
48         }));
49         Optional<String> max3 = listStr.stream().max(Comparator.comparing((x) -> {
50             return -1;
51         }));
52         // 要看comparing内部的实现Function keyExtractor  (c1, c2) -> keyExtractor.apply(c1).compareTo(keyExtractor.apply(c2));
53         System.out.println("max1=" + max1.get() + ", max2=" + max2.get() + ", max3=" + max3.get());  // max1=weoujgsd, max2=adnm, max3=adnm
54 
55         // 简写形式——使用了静态方法Comparator.comparing,比较的是length属性,
56         Optional<String> max1_1 = listStr.stream().max(Comparator.comparing(String::length));  // String::compareTo报错
57         System.out.println("简写_最长的字符串 max1_1:" + max1_1.get());
58     }
59 }
View Code

结果:

optionalMax1=xbangd, optionalMax2=xbangd
optionalMax3=adnm, optionalMax4=w3
optionalMax5=adnm
optionalMax6=weoujgsd
max1=weoujgsd, max2=adnm, max3=adnm
简写_最长的字符串 max1_1:weoujgsd

 

 

 

参考文献:

1.https://zhuanlan.zhihu.com/p/340538961

2.https://blog.csdn.net/yczz/article/details/50896975

3.https://blog.csdn.net/love905661433/article/details/86422169

posted on 2021-11-16 11:13  gogoy  阅读(56)  评论(0编辑  收藏  举报

导航