Java8新特性概述

image.png


Lambda表达式

1.Lambda表达式使用前后的对比:
举例一:

  1. @Test
  2. public void test1(){
  3. Runnable r1 = new Runnable() {
  4. @Override
  5. public void run() {
  6. System.out.println("我爱中国!");
  7. }
  8. };
  9. r1.run();
  10. System.out.println("*************************");
  11. Runnable r2 = () -> System.out.println("我爱河南!");
  12. r2.run();
  13. }

举例二:

  1. @Test
  2. public void test2(){
  3. Comparator<Integer> com1 = new Comparator<Integer>() {
  4. @Override
  5. public int compare(Integer o1, Integer o2) {
  6. return Integer.compare(o1,o2);
  7. }
  8. };
  9. int compare1 = com1.compare(12, 21);
  10. System.out.println(compare1);
  11. System.out.println("**************************");
  12. //Lambda表达式的写法
  13. Comparator<Integer> com2 = (o1, o2) -> Integer.compare(o1, o2);
  14. int compare2 = com2.compare(32, 21);
  15. System.out.println(compare2);
  16. System.out.println("***************************");
  17. //方法引用
  18. Comparator<Integer> com3 = Integer :: compare;
  19. int compare3 = com3.compare(32, 21);
  20. System.out.println(compare3);
  21. }

2.Lambda表达式的基本语法:

1.举例:(o1, o2) -> Integer.compare(o1, o2);
2.格式:
-> :Lambda操作符 或 箭头操作符
->左边:Lambda形参列表(其实就是接口中的抽象方法的形参列表)
* ->右边:Lambda体(其实就是重写的抽象方法的方法体)

3.如何使用:分六种情况
image.png
image.png

总结六种情况:

->左边:Lambda形参列表的参数类型可以省略(类型推断);如果参数列表只有一个参数,其一对()也可以省略
->右边:Lambda体应该使用一对{}包裹;如果Lambda体只有一条执行语句(可能是return语句),省略这一对{}和return关键字



函数式接口

1.函数式接口的使用说明

> 如果一个接口中,只声明了一个抽象方法,则此接口就称为函数接口。 > 我们可以在一个接口上使用@FunctionalInterface注解,这样做可以检查它是否是一个函数式接口。 > Lambda表达式的本质:作为函数式接口的实例

2.Java8 中关于Lambda表达式提供的4个基本的函数式接口:
具体使用:
image.png

3.总结

3.1何时使用Lambda表达式? 当需要对一个函数式接口实例化的时候,可以使用Lambda表达式
3.2何时使用给定的函数式接口? 如果我们开发中需要定义一个函数式接口,首先看看在已有的JDK提供的函数式接口是否提供了能满足需求的函数式接口。如果有,则直接调用即可,不需要自己再自定义。



方法引用

1.理解:

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

2.使用情景:

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

3.格式:

类(或对象) :: 方法名

4.分为如下的三种情况:

情况一 对象 :: 非静态方法
情况二 类 :: 静态方法
情况三 类 :: 非静态方法

5.要求:

> 接口中的抽象方法的形参列表和返回值类型与方法引用的方法的形参列表和返回值类型形同(针对于情况一和情况二) > 当函数式接口方法的第一个参数是需要引用方法的调用者,并且第二个参数是需要引用方法的参数(或无参数)时:ClassName::methodName

6.使用建议:

如果给函数式接口提供实例,恰好满足方法引用的使用情景,大家就可以考虑使用方法引用给函数式接口提供实例。如果大家不熟悉方法引用,那么还可以使用Lambda表达式

7.使用举例:

  1. // 情况一:对象 :: 实例方法
  2. //Consumer中的void accept(T t)
  3. //PrintStream中的void println(T t)
  4. @Test
  5. public void test1() {
  6. Consumer<String> con1 = str -> System.out.println(str);
  7. con1.accept("北京");
  8. System.out.println("************************************");
  9. PrintStream ps = System.out;
  10. Consumer<String> con2 = ps::println;
  11. con2.accept("北京");
  12. }
  13. //Supplier中的T get()
  14. //Employee中的String getName()
  15. @Test
  16. public void test2() {
  17. Employee emp = new Employee(1001,"Tom",23,5600);
  18. Supplier<String> sup1 = () -> emp.getName();
  19. System.out.println(sup1.get());
  20. System.out.println("***************************");
  21. Supplier<String> sup2 = emp::getName;
  22. System.out.println(sup2.get());
  23. }
  24. // 情况二:类 :: 静态方法
  25. //Comparator中的int compare(T t1,T t2)
  26. //Integer中的int compare(T t1,T t2)
  27. @Test
  28. public void test3() {
  29. Comparator<Integer> com1 = (t1, t2) -> Integer.compare(t1, t2);
  30. System.out.println(com1.compare(12, 21));
  31. System.out.println("**********************************");
  32. Comparator<Integer> com2 = Integer::compare;
  33. System.out.println(com2.compare(12, 3));
  34. }
  35. //Function中的R apply(T t)
  36. //Math中的Long round(Double d)
  37. @Test
  38. public void test4() {
  39. Function<Double,Long> func1 = d -> Math.round(d);
  40. System.out.println(func1.apply(12.3));
  41. System.out.println("**************************************");
  42. Function<Double,Long> func2 = Math::round;
  43. System.out.println(func2.apply(12.3));
  44. }
  45. // 情况三:类 :: 实例方法(有难度)
  46. // Comparator中的int comapre(T t1,T t2)
  47. // String中的int t1.compareTo(t2)
  48. @Test
  49. public void test5() {
  50. Comparator<String> com = new Comparator<String>() {
  51. @Override
  52. public int compare(String o1, String o2) {
  53. return o1.compareTo(o2);
  54. }
  55. };
  56. com.compare("sss", "asd");
  57. Comparator<String> com1 = (s1, s2) -> s1.compareTo(s2);
  58. com1.compare("abc", "abd");
  59. System.out.println("******************************");
  60. Comparator<String> com2 = String::compareTo;
  61. System.out.println(com2.compare("abc", "abm"));
  62. }
  63. //BiPredicate中的boolean test(T t1, T t2);
  64. //String中的boolean t1.equals(t2)
  65. @Test
  66. public void test6() {
  67. BiPredicate<String, String> pre1 = (s1, s2) -> s1.equals(s2);
  68. System.out.println(pre1.test("abc", "abc"));
  69. System.out.println("********************************");
  70. BiPredicate<String, String> pre2 = String::equals;
  71. System.out.println(pre2.test("abd", "abc"));
  72. }
  73. // Function中的R apply(T t)
  74. // Employee中的String getName();
  75. @Test
  76. public void test7() {
  77. Employee emp = new Employee(1001,"Tom",23,5600);
  78. Function<Employee, String> func1 = e -> e.getName();
  79. System.out.println(func1.apply(emp));
  80. System.out.println("*********************************");
  81. Function<Employee, String> func2 = Employee::getName;
  82. System.out.println(func2.apply(emp));
  83. }

构造器引用与数组引用

1.构造器引用的格式:

类名 :: new

2.构造器引用使用要求:

和方法引用类似,函数式接口的抽象方法的形参列表和构造器的形参列表一致抽象方法的返回值类型即为构造器所属的类的类型

3.构造器引用举例:

  1. //Supplier中的T get()
  2. @Test
  3. public void test1(){
  4. Supplier<Employee> sup1 = () -> new Employee();
  5. System.out.println(sup1.get());
  6. System.out.println("********************************");
  7. Supplier<Employee> sup2 = Employee::new;
  8. System.out.println(sup2.get());
  9. }
  10. //Function中的R apply(T t)
  11. @Test
  12. public void test2(){
  13. Function<Integer, Employee> func1 = id -> new Employee(id);
  14. Employee employee = func1.apply(1001);
  15. System.out.println(employee);
  16. System.out.println("******************************");
  17. Function<Integer, Employee> func2 = Employee::new;
  18. System.out.println(func2.apply(1002));
  19. }
  20. //BiFunction中的R apply(T t,U u)
  21. @Test
  22. public void test3(){
  23. BiFunction<Integer, String, Employee> func1 = (id, name) -> new Employee(id, name);
  24. System.out.println(func1.apply(1001, "Tom"));
  25. System.out.println("****************************************");
  26. BiFunction<Integer, String, Employee> func2 = Employee::new;
  27. System.out.println(func2.apply(1002, "Tom"));
  28. }

**

4.数组引用格式:

数组类型[ ] :: new

5.数组引用举例:

  1. //Function中的R apply(T t)
  2. @Test
  3. public void test4(){
  4. Function<Integer, String[]> func1 = length -> new String[length];
  5. String[] arr1 = func1.apply(5);
  6. System.out.println(Arrays.toString(arr1));
  7. System.out.println("*******************************");
  8. Function<Integer, String[]> func2 = String[]::new;
  9. String[] arr2 = func1.apply(10);
  10. System.out.println(Arrays.toString(arr2));
  11. }

**



Stream API

1.Stream API的理解:

① Stream关注的是对数据的运算,与CPU打交道。集合关注的是数据的存储,与内存打交道 ② Java8提供了一套API,使用这套API可以对内存中的数据进行过滤、排序、映射、规约等操作。类似于SQL对数据库表的相关操作

2.注意点:

①Stream 自己不会存储元素 ②Stream 不会改变源对象。相反,他们会返回一个持有结果的新Stream ③Stream 操作是延迟执行的。这意味着他们会等到需要结果的时候才执行

3.Stream的使用流程:

① Stream的实例化
② 一系列的中间操作(过滤、映射、…)
③ 终止操作

4.使用流程的注意点:

① 一个中间操作链,对数据源的数据进行处理
② 一旦执行终止操作,就执行中间操作链,并产生结果。之后,不会再被使用

5.步骤一:Stream实例化

  1. //创建 Stream方式一:通过集合
  2. @Test
  3. public void test1(){
  4. List<Employee> employees = EmployeeData.getEmployees();
  5. //default Stream<E> stream() : 返回一个顺序流
  6. Stream<Employee> stream = employees.stream();
  7. //default Stream<E> parallelStream() : 返回一个并行流
  8. Stream<Employee> parallelStream = employees.parallelStream();
  9. }
  10. //创建 Stream方式二:通过数组
  11. @Test
  12. public void test2(){
  13. int[] arr = new int[]{1,2,2,3,5,5,5};
  14. //调用Arrays类的static <T> Stream<T> stream(T[] array): 返回一个流
  15. IntStream stream = Arrays.stream(arr);
  16. Employee e1 = new Employee(1001,"Tom");
  17. Employee e2 = new Employee(1002,"Tm");
  18. Employee[] arr1 = new Employee[]{e1,e2};
  19. Stream<Employee> stream1 = Arrays.stream(arr1);
  20. }
  21. //创建 Stream方式三:通过Stream的of()
  22. @Test
  23. public void test3(){
  24. Stream<Integer> stream = Stream.of(1, 2, 3, 4, 5, 6);
  25. }
  26. //创建 Stream方式四:创建无限流
  27. @Test
  28. public void test4(){
  29. //迭代
  30. //public static<T> Stream<T> iterate(final T seed, final UnaryOperator<T> f)
  31. //遍历前10个偶数
  32. Stream.iterate(0, t -> t + 2).limit(10).forEach(System.out::println);
  33. //生成
  34. //public static<T> Stream<T> generate(Supplier<T> s)
  35. Stream.generate(Math::random).limit(10).forEach(System.out::println);
  36. }


6.步骤二:中间操作
image.png
image.png
image.png

7.步骤三:终止操作
image.png
image.png
image.png
image.png
Collector需要使用Collectors提供实例

image.png


Optional类的使用

java.lang.Optional类
1.理解:为了解决java中的空指针问题而生

Optional 类(java.util.Optional) 是一个容器类,它可以保存类型T的值,代表这个值存在。或者仅仅保存null,表示这个值不存在。原来用null表示一个值不存在,现在Optional可以更好的表达这个概念。并且可以避免空指针异常。

2.常用方法:

  1. @Test
  2. public void test1(){
  3. //empty():创建的Optional对象内部的value = null
  4. Optional<Object> op1 = Optional.empty();
  5. if (!op1.isPresent()){//Optional封装数据是否包含数据
  6. System.out.println("数据为空");
  7. }
  8. System.out.println(op1.isPresent());
  9. System.out.println(op1);
  10. //如果Optional封装的数据value为空,则get()报错。value不为空时,返回value
  11. // System.out.println(op1.get());
  12. }
  13. @Test
  14. public void test2(){
  15. String str = "hello";
  16. //of(T t):封装数据t生成Optional对象。要求t非空,否则报错
  17. Optional<String> op1 = Optional.of(str);
  18. //get()通常与of()方法搭配使用。用于获取内部封装的数据value
  19. String str1 = op1.get();
  20. System.out.println(str1);
  21. }
  22. @Test
  23. public void test3(){
  24. String str = "beijing";
  25. //ofNullable(T t):封装数据t赋给Optional内部的value。不要求t非空
  26. Optional<String> op1 = Optional.ofNullable(str);
  27. //orElse(T t1):如果Optional内部的value非空,则返回此value值
  28. //如果value为空,则返回t1
  29. String str2 = op1.orElse("shanghai");
  30. System.out.println(str2);
  31. }

3.典型练习:
能保证如下的方法执行中不会出现空指针的异常

  1. //使用Optional类的getGirlName()
  2. public String getGirlName2(Boy boy){
  3. Optional<Boy> boyOptional = Optional.ofNullable(boy);
  4. //此时的boy1一定非空
  5. Boy boy1 = boyOptional.orElse(new Boy(new Girl("迪丽热巴")));
  6. Girl girl = boy1.getGirl();
  7. Optional<Girl> girlOptional = Optional.ofNullable(girl);
  8. //此时girl1一定非空
  9. Girl girl1 = girlOptional.orElse(new Girl("古力娜扎"));
  10. return girl1.getName();
  11. }
  12. @Test
  13. public void test5(){
  14. Boy boy = new Boy();
  15. String girlName2 = getGirlName2(boy);
  16. System.out.println(girlName2);
  17. }