H__D  

Java 8新特性简介

  • 速度更快
  • 代码更少(增加了新的语法:Lambda 表达式)  
  • 强大的 Stream API
  • 便于并行
  • 最大化减少空指针异常:Optional
  • Nashorn引擎,允许在JVM上运行JS应用

Lambda 表达式

  Lambda 是一个匿名函数,我们可以把 Lambda 表达式理解为是一段可以 传递的代码(将代码像数据一样进行传递)。使用它可以写出更简洁、更 灵活的代码。作为一种更紧凑的代码风格,使Java的语言表达能力得到了 提升

  Lambda 表达式:在Java 8 语言中引入的一种新的语法元素和操 作符。这个操作符为 “->” , 该操作符被称为 Lambda 操作符 或箭头操作符。

  它将 Lambda 分为两个部分:

  左侧:指定了 Lambda 表达式需要的参数列表

  右侧:指定了 Lambda 体,是抽象方法的实现逻辑,也即 Lambda 表达式要执行的功能。

Lambda表达式的使用

  1.举例: (o1,o2) -> Integer.compare(o1,o2);

  2.格式:
    -> :lambda操作符 或 箭头操作符
    ->左边:lambda形参列表 (其实就是接口中的抽象方法的形参列表)
    ->右边:lambda体 (其实就是重写的抽象方法的方法体)

  3.Lambda表达式的使用:(分为6种情况介绍)
    总结:
    ->左边:lambda形参列表的参数类型可以省略(类型推断);如果lambda形参列表只有一个参数,其一对()也可以省略
    ->右边:lambda体应该使用一对{}包裹;如果lambda体只有一条执行语句(可能是return语句),省略这一对{}和return关键字

  4.Lambda表达式的本质:作为函数式接口的实例

  5. 如果一个接口中,只声明了一个抽象方法,则此接口就称为函数式接口。我们可以在一个接口上使用 @FunctionalInterface 注解,
  这样做可以检查它是否是一个函数式接口。

  6. 所以以前用匿名实现类表示的现在都可以用Lambda表达式来写。

从匿名类到 Lambda 的转换举例  

 1 public class LambdaTest {
 2 
 3     @Test
 4     public void test1(){
 5         Runnable r1 = new Runnable() {
 6             public void run() {
 7                 System.out.println("我爱北京天安门");
 8             }
 9         };
10         r1.run();
11 
12         System.out.println("***********************");
13 
14         Runnable r2 = () -> System.out.println("我爱北京故宫");
15         r2.run();
16     }
17 
18     @Test
19     public void test2(){
20         Comparator<Integer> com1 = new Comparator<Integer>() {
21             @Override
22             public int compare(Integer o1, Integer o2) {
23                 return Integer.compare(o1, o2);
24             }
25         };
26 
27         int compare1 = com1.compare(12, 21);
28         System.out.println(compare1);
29 
30         System.out.println("***********************");
31 
32         //Lambda表达式的写法
33         Comparator<Integer> com2 = (o1, o2) -> Integer.compare(o1, o2);
34         System.out.println(com2.compare(32, 21));
35 
36         System.out.println("***********************");
37 
38         //方法引用
39         Comparator<Integer> com3 = Integer::compareTo;
40         System.out.println(com3.compare(32, 21));
41     }
42 }

 Lambda表达式的使用举例

  1 /**
  2  * Lambda表达式的使用
  3  *
  4  * 1.举例: (o1,o2) -> Integer.compare(o1,o2);
  5  * 2.格式:
  6  *      -> :lambda操作符 或 箭头操作符
  7  *      ->左边:lambda形参列表 (其实就是接口中的抽象方法的形参列表)
  8  *      ->右边:lambda体 (其实就是重写的抽象方法的方法体)
  9  *
 10  * 3. Lambda表达式的使用:(分为6种情况介绍)
 11  *
 12  *    总结:
 13  *    ->左边:lambda形参列表的参数类型可以省略(类型推断);如果lambda形参列表只有一个参数,其一对()也可以省略
 14  *    ->右边:lambda体应该使用一对{}包裹;如果lambda体只有一条执行语句(可能是return语句),省略这一对{}和return关键字
 15  *
 16  * 4.Lambda表达式的本质:作为函数式接口的实例
 17  *
 18  * 5. 如果一个接口中,只声明了一个抽象方法,则此接口就称为函数式接口。我们可以在一个接口上使用 @FunctionalInterface 注解,
 19  *   这样做可以检查它是否是一个函数式接口。
 20  *
 21  * 6. 所以以前用匿名实现类表示的现在都可以用Lambda表达式来写。
 22  *
 23  */
 24 public class LambdaTest1 {
 25 
 26     //语法格式一:无参,无返回值
 27     @Test
 28     public void test1(){
 29         Runnable r1 = new Runnable() {
 30             @Override
 31             public void run() {
 32                 System.out.println("我爱北京天安门");
 33             }
 34         };
 35 
 36         r1.run();
 37 
 38         System.out.println("***********************");
 39 
 40         Runnable r2 = () -> {
 41             System.out.println("我爱北京故宫");
 42         };
 43 
 44         r2.run();
 45     }
 46 
 47     //语法格式二:Lambda 需要一个参数,但是没有返回值。
 48     @Test
 49     public void test2(){
 50         Consumer<String> con = new Consumer<String>() {
 51             @Override
 52             public void accept(String s) {
 53                 System.out.println(s);
 54             }
 55         };
 56 
 57         con.accept("谎言和誓言的区别是什么?");
 58 
 59         System.out.println("***********************");
 60 
 61         Consumer<String> con1 = (String s) -> {
 62             System.out.println(s);
 63         };
 64 
 65         con1.accept("一个是听的人当真了,一个是说的人当真了");
 66     }
 67 
 68     //语法格式三:数据类型可以省略,因为可由编译器推断得出,称为“类型推断”
 69     @Test
 70     public void test3(){
 71         Consumer<String> con1 = (String s) -> {
 72             System.out.println(s);
 73         };
 74 
 75         con1.accept("一个是听的人当真了,一个是说的人当真了");
 76 
 77         System.out.println("***********************");
 78 
 79         Consumer<String> con2 = (s) -> {
 80             System.out.println(s);
 81         };
 82 
 83         con2.accept("一个是听的人当真了,一个是说的人当真了");
 84     }
 85 
 86     @Test
 87     public void test4(){
 88         ArrayList<String> list = new ArrayList<>();// 类型推断
 89         int[] arr = {1, 2, 3};// 类型推断
 90     }
 91 
 92     //语法格式四:Lambda 若只需要一个参数时,参数的小括号可以省略
 93     @Test
 94     public void test5(){
 95         Consumer<String> con1 = (s) -> {
 96             System.out.println(s);
 97         };
 98 
 99         con1.accept("一个是听的人当真了,一个是说的人当真了");
100 
101         System.out.println("***********************");
102 
103         Consumer<String> con2 = s -> {
104             System.out.println(s);
105         };
106 
107         con2.accept("一个是听的人当真了,一个是说的人当真了");
108     }
109 
110     //语法格式五:Lambda 需要两个或以上的参数,多条执行语句,并且可以有返回值
111     @Test
112     public void test6(){
113         Comparator<Integer> com1 = new Comparator<Integer>() {
114             @Override
115             public int compare(Integer o1, Integer o2) {
116                 System.out.println(o1);
117                 System.out.println(02);
118                 return o1.compareTo(o2);
119             }
120         };
121 
122         System.out.println(com1.compare(12, 21));
123 
124         System.out.println("***********************");
125 
126         Comparator<Integer> com2 = (o1, o2) -> {
127             System.out.println(o1);
128             System.out.println(02);
129             return o1.compareTo(o2);
130         };
131 
132         System.out.println(com2.compare(12, 6));
133     }
134 
135     //语法格式六:当 Lambda 体只有一条语句时,return 与大括号若有,都可以省略
136     @Test
137     public void test7(){
138         Comparator<Integer> com1 = (o1, o2) -> {
139             return o1.compareTo(o2);
140         };
141         System.out.println(com1.compare(12, 6));
142 
143         System.out.println("***********************");
144 
145         Comparator<Integer> com2 = (o1, o2) -> o1.compareTo(o2);
146         System.out.println(com2.compare(12, 21));
147     }
148 
149     @Test
150     public void test8(){
151         Consumer<String> con1 = s -> {
152             System.out.println(s);
153         };
154 
155         con1.accept("一个是听的人当真了,一个是说的人当真了");
156 
157         System.out.println("***********************");
158 
159         Consumer<String> con2 = s -> System.out.println(s);
160         con2.accept("一个是听的人当真了,一个是说的人当真了");
161     }
162 
163 
164 }

函数式(Functional)接口

  • 只包含一个抽象方法的接口,称为函数式接口。

  • 你可以通过 Lambda 表达式来创建该接口的对象。(若 Lambda 表达式抛出一个受检异常(即:非运行时异常),那么该异常需要在目标接口的抽象方法上进行声明)。

  • 我们可以在一个接口上使用 @FunctionalInterface 注解,这样做可以检查它是否是一个函数式接口。同时 javadoc 也会包含一条声明,说明这个接口是一个函数式接口。

  • 在java.util.function包下定义了Java 8 的丰富的函数式接口

自定义函数式接口

 1 /**
 2  * 自定义函数式接口
 3  */
 4 @FunctionalInterface
 5 public interface MyInterface {
 6 
 7     void method1();
 8 
 9 //    void method2();
10 }

Java 内置四大核心函数式接口

  

其他函数式接口

  

函数式接口举例

 1 /**
 2  * java内置的4大核心函数式接口
 3  * <p>
 4  * 消费型接口 Consumer<T>     void accept(T t)
 5  * 供给型接口 Supplier<T>     T get()
 6  * 函数型接口 Function<T,R>   R apply(T t)
 7  * 断定型接口 Predicate<T>    boolean test(T t)
 8  */
 9 public class LambdaTest2 {
10 
11     // 消费型接口 Consumer<T>     void accept(T t)
12     @Test
13     public void test1() {
14         happyTime(500, new Consumer<Double>() {
15             @Override
16             public void accept(Double aDouble) {
17                 System.out.println("学习太累了,去天上人间买了瓶矿泉水,价格为:" + aDouble);
18             }
19         });
20 
21         System.out.println("********************");
22 
23         happyTime(400, money -> System.out.println("学习太累了,去天上人间喝了口水,价格为:" + money));
24 
25     }
26 
27     public void happyTime(double money, Consumer<Double> con) {
28         con.accept(money);
29     }
30 
31 
32     @Test
33     public void test2() {
34         List<String> list = Arrays.asList("北京", "南京", "天津", "东京", "西京", "普京");
35 
36         List<String> filterStrs = filterString(list, new Predicate<String>() {
37             @Override
38             public boolean test(String s) {
39                 return s.contains("京");
40             }
41         });
42 
43         System.out.println(filterStrs);
44 
45         List<String> filterStrs1 = filterString(list, s -> s.contains("京"));
46         System.out.println(filterStrs1);
47     }
48 
49     //根据给定的规则,过滤集合中的字符串。此规则由Predicate的方法决定
50     public List<String> filterString(List<String> list, Predicate<String> pre) {
51         ArrayList<String> filterList = new ArrayList<>();
52         for (String s : list) {
53             if(pre.test(s)) {
54                 filterList.add(s);
55             }
56         }
57         return filterList;
58     }
59 }

方法引用(Method References)

  • 当要传递给Lambda体的操作,已经有实现的方法了,可以使用方法引用!

  • 方法引用可以看做是Lambda表达式深层次的表达。换句话说,方法引用就 是Lambda表达式,也就是函数式接口的一个实例,通过方法的名字来指向 一个方法,可以认为是Lambda表达式的一个语法糖。

  • 要求:实现接口的抽象方法的参数列表和返回值类型,必须与方法引用的 方法的参数列表和返回值类型保持一致!

  • 格式:使用操作符 “::” 将类(或对象) 与 方法名分隔开来。

  • 如下三种主要使用情况:

     对象::实例方法名  类::静态方法名  类::实例方法名

方法引用的使用

  1 /**
  2  * 方法引用的使用
  3  *
  4  * 1.使用情境:当要传递给Lambda体的操作,已经有实现的方法了,可以使用方法引用!
  5  *
  6  * 2.方法引用,本质上就是Lambda表达式,而Lambda表达式作为函数式接口的实例。所以
  7  *   方法引用,也是函数式接口的实例。
  8  *
  9  * 3. 使用格式:  类(或对象) :: 方法名
 10  *
 11  * 4. 具体分为如下的三种情况:
 12  *    情况1     对象 :: 非静态方法
 13  *    情况2     类 :: 静态方法
 14  *
 15  *    情况3     类 :: 非静态方法
 16  *
 17  * 5. 方法引用使用的要求:要求接口中的抽象方法的形参列表和返回值类型与方法引用的方法的
 18  *    形参列表和返回值类型相同!(针对于情况1和情况2)
 19  *
 20  */
 21 public class MethodRefTest {
 22 
 23     // 情况一:对象 :: 实例方法
 24     //Consumer中的void accept(T t)
 25     //PrintStream中的void println(T t)
 26     @Test
 27     public void test1(){
 28         Consumer<String> con1 = str -> System.out.println(str);
 29         con1.accept("北京");
 30 
 31         System.out.println("*******************");
 32 
 33         Consumer<String> con2 = System.out :: println;
 34         con2.accept("beijing");
 35     }
 36 
 37     //Supplier中的T get()
 38     //Employee中的String getName()
 39     @Test
 40     public void test2(){
 41         Employee emp = new Employee(1001,"Tom",23,5600);
 42 
 43         Supplier<String> sup1 = () -> emp.getName();
 44         System.out.println(sup1.get());
 45 
 46         System.out.println("*******************");
 47 
 48         Supplier<String> sup2 = emp::getName;
 49         System.out.println(sup2.get());
 50     }
 51 
 52 
 53     // 情况二:类 :: 静态方法
 54     //Comparator中的int compare(T t1,T t2)
 55     //Integer中的int compare(T t1,T t2)
 56     @Test
 57     public void test3(){
 58         Comparator<Integer> com1 = (t1, t2) -> Integer.compare(t1, t2);
 59         System.out.println(com1.compare(12, 21));
 60 
 61         System.out.println("*******************");
 62 
 63         Comparator<Integer> com2 = Integer::compare;
 64         System.out.println(com2.compare(12, 8));
 65 
 66     }
 67 
 68     //Function中的R apply(T t)
 69     //Math中的Long round(Double d)
 70     @Test
 71     public void test4(){
 72         Function<Double, Long> func = new Function<Double, Long>() {
 73             @Override
 74             public Long apply(Double aDouble) {
 75                 return Math.round(aDouble);
 76             }
 77         };
 78         System.out.println(func.apply(12.3));
 79 
 80         System.out.println("*******************");
 81 
 82         Function<Double, Long> func1 = d -> Math.round(d);
 83         System.out.println(func1.apply(12.6));
 84 
 85         System.out.println("*******************");
 86 
 87         Function<Double, Long> func2 = Math::round;
 88         System.out.println(func2.apply(12.7));
 89     }
 90 
 91     // 情况三:类 :: 实例方法  (有难度)
 92     // Comparator中的int comapre(T t1,T t2)
 93     // String中的int t1.compareTo(t2)
 94     @Test
 95     public void test5(){
 96         Comparator<String> com1 = (s1, s2) -> s1.compareTo(s2);
 97         System.out.println(com1.compare("abc", "abd"));
 98 
 99         System.out.println("*******************");
100 
101         Comparator<String> com2 = String::compareTo;
102         System.out.println(com2.compare("abc", "abe"));
103     }
104 
105     //BiPredicate中的boolean test(T t1, T t2);
106     //String中的boolean t1.equals(t2)
107     @Test
108     public void test6(){
109         BiPredicate<String, String> pre1 =  (s1, s2) -> s1.equals(s2);
110         System.out.println(pre1.test("abc", "abc"));
111 
112         System.out.println("*******************");
113 
114         BiPredicate<String, String> pre2 = String::equals;
115         System.out.println(pre2.test("abc", "abd"));
116     }
117 
118     // Function中的R apply(T t)
119     // Employee中的String getName();
120     @Test
121     public void test7(){
122         Employee employee = new Employee(1001, "Jerry", 23, 6000);
123 
124         Function<Employee, String> func1 = e -> e.getName();
125         System.out.println(func1.apply(employee));
126 
127         System.out.println("*******************");
128 
129         Function<Employee, String> func2 = Employee::getName;
130         System.out.println(func2.apply(employee));
131     }
132 }

构造器引用

  与函数式接口相结合,自动与函数式接口中方法兼容。 可以把构造器引用赋值给定义的方法,要求构造器参数列表要与接口中抽象 方法的参数列表一致!且方法的返回值即为构造器对应类的对象。

 构造器引用使用

 1 /**
 2  * 一、构造器引用
 3  *      和方法引用类似,函数式接口的抽象方法的形参列表和构造器的形参列表一致。
 4  *      抽象方法的返回值类型即为构造器所属的类的类型
 5  *
 6  * 二、数组引用
 7  *     大家可以把数组看做是一个特殊的类,则写法与构造器引用一致。
 8  *
 9  * 三、格式
10  *     类(或数组) :: new
11  *
12  */
13 public class ConstructorRefTest {
14 
15     //构造器引用
16     //Supplier中的T get()
17     //Employee的空参构造器:Employee()
18     @Test
19     public void test1(){
20         Supplier<Employee> sup = new Supplier<Employee>() {
21             @Override
22             public Employee get() {
23                 return new Employee();
24             }
25         };
26         System.out.println("*******************");
27 
28         Supplier<Employee> sup1 = () -> new Employee();
29         System.out.println(sup1.get());
30 
31         System.out.println("*******************");
32 
33         Supplier<Employee> sup2 = Employee::new;
34         System.out.println(sup2.get());
35     }
36 
37     //Function中的R apply(T t)
38     @Test
39     public void test2(){
40         Function<Integer, Employee> func1 = id -> new Employee(id);
41         System.out.println(func1.apply(1001));
42 
43         System.out.println("*******************");
44 
45         Function<Integer, Employee> func2 = Employee::new;
46         System.out.println(func2.apply(1002));
47     }
48 
49     //BiFunction中的R apply(T t,U u)
50     @Test
51     public void test3(){
52         BiFunction<Integer, String, Employee> func1 = (id, name) -> new Employee(id, name);
53         System.out.println(func1.apply(1001, "Tom"));
54 
55         System.out.println("*******************");
56 
57         BiFunction<Integer, String, Employee> func2 = Employee::new;
58         System.out.println(func2.apply(1002, "Tom"));
59     }
60 
61     //数组引用
62     //Function中的R apply(T t)
63     @Test
64     public void test4(){
65         Function<Integer, String[]> func1 = length -> new String[length];
66         String[] arr1 = func1.apply(5);
67         System.out.println(Arrays.toString(arr1));
68 
69         System.out.println("*******************");
70 
71         Function<Integer, String[]> func2 = String[]::new;
72         String[] arr2 = func2.apply(6);
73         System.out.println(Arrays.toString(arr2));
74     }
75 }

 

 

 

 

posted on 2021-02-26 22:45  H__D  阅读(29)  评论(0编辑  收藏