• Java8新特性


    目录

    1.Lambad表达式

     Lambda表达式语法

    函数式接口

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

    方法引用

    2.Stream

    Stream的操作三个步骤

    创建Stream流的三种方式

    Stream的中间操作:筛选与切片 

    Stream的中间操作:映射 

     Stream的中间操作:排序

    Stream的终止操作:匹配与查找

    Stream的终止操作:归约

    Stream的终止操作:收集

    3.Optional类


    1.Lambad表达式

    Lambda 表达式,也可称为闭包,它是推动 Java 8 发布的最重要新特性。

    Lambda 允许把函数作为一个方法的参数(函数作为参数传递进方法中)。

    使用 Lambda 表达式可以使代码变的更加简洁紧凑。

    lambda 表达式的语法格式如下:

    (parameters) -> expression

    或 (parameters) ->{ statements; }

    例如:

    1. new Thread(new Runnable() {
    2. @Override
    3. public void run() {
    4. System.out.println("running");
    5. }
    6. }).start();
    7. //lambda表达式
    8. new Thread(
    9. ()-> System.out.println("running")
    10. ).start();
    1. Comparator<Integer> comparator=new Comparator<Integer>() {
    2. @Override
    3. public int compare(Integer o1, Integer o2) {
    4. return Integer.compare(o1,o2);
    5. }
    6. };
    7. int compare = comparator.compare(12, 13);
    8. System.out.println(compare);
    9. //****************************
    10. //lambda表达式
    11. Comparator<Integer> comparator2=(o1, o2) ->Integer.compare(o1,o2);
    12. //方法引用
    13. Comparator<Integer> comparator3=Integer::compare;

    1. 函数式接口,不用知道方法名。

    2.通过泛型得知参数类型,不用知道具体的数据类型

    3. 直接返回调用的结果

    函数式接口:接口中一定要只有一个抽象方法才可以这么写。这也是Java8在接口中引入静态和默认方法的原因。

     Lambda表达式语法

    格式:
    ->:Lambda操作符或箭头操作符

    ->左边: Lambda形参列表(其实就是接口中的抽象方法的形参列表)

    ->右边: Lambda体(其实就是重写的抽象方法的方法体)I

    语法格式1:无参,无返回值

    1. new Thread(new Runnable() {
    2. @Override
    3. public void run() {
    4. System.out.println("running");
    5. }
    6. }).start();
    7. //lambda表达式
    8. new Thread(
    9. ()-> System.out.println("running")
    10. ).start();

    语法格式2:一个参数,无返回值 

    1. Consumer<String> consumer=new Consumer<String>() {
    2. @Override
    3. public void accept(String s) {
    4. System.out.println(s);
    5. }
    6. };
    7. consumer.accept("普通的接口实现");
    8. //************************************
    9. Consumer<String> consumer2=(String s)->System.out.println(s);
    10. consumer2.accept("Lambda表达式");

    语法格式3:数据类型可以省略,因为可由编译器推断得出,称为“类型推断” 

    1. Consumer<String> consumer=new Consumer<String>() {
    2. @Override
    3. public void accept(String s) {
    4. System.out.println(s);
    5. }
    6. };
    7. consumer.accept("普通的接口实现");
    8. //************************************
    9. Consumer<String> consumer2=(s)->System.out.println(s); //因为泛型把类型定死了
    10. consumer2.accept("Lambda表达式");

    语法格式4: Lambda若只需要一个参数,参数的小括号可以省略

    1. Consumer<String> consumer=new Consumer<String>() {
    2. @Override
    3. public void accept(String s) {
    4. System.out.println(s);
    5. }
    6. };
    7. consumer.accept("普通的接口实现");
    8. //************************************
    9. Consumer<String> consumer2=s->System.out.println(s); //单参数省略小括号
    10. consumer2.accept("Lambda表达式");

    语法格式5:Lambda需要两个或以上的参数,多条执行语句,并且可以有返回值

    1. Comparator<Integer> comparator = new Comparator<Integer>() {
    2. @Override
    3. public int compare(Integer o1, Integer o2) {
    4. return o1.compareTo(o2);
    5. }
    6. };
    7. Comparator<Integer> comparator2=(o1, o2) -> {return o1.compareTo(o2); };

    语法格式六:当Lambda体只有一条语句时,return 与大括号若有,都可以省略 

    1. Comparator<Integer> comparator = new Comparator<Integer>() {
    2. @Override
    3. public int compare(Integer o1, Integer o2) {
    4. return o1.compareTo(o2);
    5. }
    6. };
    7. Comparator<Integer> comparator2=(o1, o2) -> o1.compareTo(o2);
    8. }

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


    函数式接口

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

     如果一个接口中,只声明了一个抽象方法,则此接口就称为函数式接口。

    我们可以在一个接口上使用 @FunctionalInterface注解 这样做可以检查它是否是一个函数式接口。

    1. /**
    2. * 自定义函数式接口
    3. */
    4. public interface MyInterFace {
    5. void method();
    6. // void method2();
    7. }

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

    JDK 1.8 之前已有的函数式接口:

    • java.lang.Runnable
    • java.util.concurrent.Callable
    • java.security.PrivilegedAction
    • java.util.Comparator
    • java.io.FileFilter
    • java.nio.file.PathMatcher
    • java.lang.reflect.InvocationHandler
    • java.beans.PropertyChangeListener
    • java.awt.event.ActionListener
    • javax.swing.event.ChangeListener

    JDK 1.8 新增加的函数接口:

    • java.util.function

     

     四大函数式接口_m0_46493091的博客-CSDN博客_四大函数式接口

    方法引用

    • 当要传递给Lambda体的操作,已经有实现的方法了,可以使用方法引用!
    • 方法引用可以看做是Lambda表达式深层次的表达。换句话说,方法引用就是Lambda表达式,也就是函数式接口的一个实例,通过方法的名字来指向一个方法,可以认为是Lambda表达式的一个语法糖
    • 要求:实现接口的抽象方法的参数列表和返回值类型,必须与方法引用的方法的参数列表和返回值类型保持一致!
    • 格式:使用操作符“::” 将类(或对象) 与方法名分隔开来。
    • 如下三种主要使用情况:
    • 对象::实例方法名
    • 类::静态方法名
    • 类::实例方法名
    1. // 情况一:对象 :: 实例方法
    2. //Consumer中的void accept(T t)
    3. //PrintStream中的void println(T t)
    4. @Test
    5. public void test() {
    6. Consumer<String> c1 = str -> System.out.println(str);
    7. c1.accept("苏州");
    8. System.out.println("+++++++++++++");
    9. PrintStream ps = System.out;
    10. Consumer<String> c2 = ps::println; //对象::实例方法名
    11. c2.accept("xian");
    12. }
    1. // 情况二:类 :: 静态方法
    2. //Comparator中的int compare(T t1,T t2)
    3. //Integer中的int compare(T t1,T t2)
    4. @Test
    5. public void test3() {
    6. Comparator<Integer> com1 = (t1, t2) -> Integer.compare(t1,t2);
    7. System.out.println(com1.compare(21,20));
    8. System.out.println("+++++++++++++++");
    9. Comparator<Integer> com2 = Integer::compare;
    10. System.out.println(com2.compare(15,7));
    11. }

    1. // 情况三:类 :: 实例方法 (有难度)
    2. // Comparator中的int comapre(T t1,T t2)
    3. // String中的int t1.compareTo(t2)
    4. @Test
    5. public void test5() {
    6. Comparator<String> com1 = (s1,s2) -> s1.compareTo(s2);
    7. System.out.println(com1.compare("abc","abd"));
    8. System.out.println("++++++++++++++++");
    9. Comparator<String> com2 = String :: compareTo;
    10. System.out.println(com2.compare("abd","abm"));
    11. }
    12. //BiPredicate中的boolean test(T t1, T t2);
    13. //String中的boolean t1.equals(t2)
    14. @Test
    15. public void test6() {
    16. BiPredicate<String,String> pre1 = (s1, s2) -> s1.equals(s2);
    17. System.out.println(pre1.test("MON","MON"));
    18. System.out.println("++++++++++++++++++++");
    19. BiPredicate<String,String> pre2 = String :: equals;
    20. System.out.println(pre2.test("MON","MON"));
    21. }

    2.Stream

    Stream流式计算,最主要是用来方便计算操作。

    • Stream 和Collection 集合的区别:Collection 是一种静态的内存数据结构,而Stream 是有关计算的。前者是主要面向内存,存储在内存中,后者主要是面向CPU,通过CPU 实现计算。

    Stream用于进行计算,是数据渠道,用于操作数据源(集合、数组等)所生成的元素序列。

    Stream并不会存储数据。(就跟迭代器相同,它们都只是一个操作工具,不存储数据)

    Stream并不会改变数据源,它会返回一个含有结果集的Stream。

    Stream是延迟加载的,在需要结果时才执行。

    Stream的操作三个步骤

    1、创建一个流。

    一个数据源(如:集合、数组),获取一个流

    2、将初始流转换为其他流的中间操作,可能包含多个步骤。

    一个中间操作链,对数据源的数据进行处理

    3、终止操作,执行终止操作后才执行中间操作链,此后这个流就不能再使用了。

    一旦执行终止操作,就执行中间操作链,并产生结果。之后,不会再被使用

    创建Stream流的三种方式

    Employee.class

    1. public class Employee {
    2. private int id;
    3. private String name;
    4. private int age;
    5. private double salary;
    6. public int getId() {
    7. return id;
    8. }
    9. public void setId(int id) {
    10. this.id = id;
    11. }
    12. public String getName() {
    13. return name;
    14. }
    15. public void setName(String name) {
    16. this.name = name;
    17. }
    18. public int getAge() {
    19. return age;
    20. }
    21. public void setAge(int age) {
    22. this.age = age;
    23. }
    24. public double getSalary() {
    25. return salary;
    26. }
    27. public void setSalary(double salary) {
    28. this.salary = salary;
    29. }
    30. public Employee() {
    31. System.out.println("Employee().....");
    32. }
    33. public Employee(int id) {
    34. this.id = id;
    35. System.out.println("Employee(int id).....");
    36. }
    37. public Employee(int id, String name) {
    38. this.id = id;
    39. this.name = name;
    40. }
    41. public Employee(int id, String name, int age, double salary) {
    42. this.id = id;
    43. this.name = name;
    44. this.age = age;
    45. this.salary = salary;
    46. }
    47. @Override
    48. public String toString() {
    49. return "Employee{" + "id=" + id + ", name='" + name + '\'' + ", age=" + age + ", salary=" + salary + '}';
    50. }
    51. @Override
    52. public boolean equals(Object o) {
    53. if (this == o)
    54. return true;
    55. if (o == null || getClass() != o.getClass())
    56. return false;
    57. Employee employee = (Employee) o;
    58. if (id != employee.id)
    59. return false;
    60. if (age != employee.age)
    61. return false;
    62. if (Double.compare(employee.salary, salary) != 0)
    63. return false;
    64. return name != null ? name.equals(employee.name) : employee.name == null;
    65. }
    66. @Override
    67. public int hashCode() {
    68. int result;
    69. long temp;
    70. result = id;
    71. result = 31 * result + (name != null ? name.hashCode() : 0);
    72. result = 31 * result + age;
    73. temp = Double.doubleToLongBits(salary);
    74. result = 31 * result + (int) (temp ^ (temp >>> 32));
    75. return result;
    76. }
    77. }

     EmployeeData.class

    1. import java.util.ArrayList;
    2. import java.util.List;
    3. /**
    4. * 提供用于测试的数据
    5. */
    6. public class EmployeeData {
    7. public static List getEmployees(){
    8. List list = new ArrayList<>();
    9. list.add(new Employee(1001, "马化腾", 34, 6000.38));
    10. list.add(new Employee(1002, "马云", 12, 9876.12));
    11. list.add(new Employee(1003, "刘强东", 33, 3000.82));
    12. list.add(new Employee(1004, "雷军", 26, 7657.37));
    13. list.add(new Employee(1005, "李彦宏", 65, 5555.32));
    14. list.add(new Employee(1006, "比尔盖茨", 42, 9500.43));
    15. list.add(new Employee(1007, "任正非", 26, 4333.32));
    16. list.add(new Employee(1008, "扎克伯格", 35, 2500.32));
    17. return list;
    18. }
    19. }
    1. /**
    2. * 测试Stream的实例化
    3. */
    4. public class Streamapi {
    5. //创建 Stream方式一:通过集合
    6. @Test
    7. public void test(){
    8. List<Employee> employees = EmployeeData.getEmployees();
    9. // default Stream stream() : 返回一个顺序流,拿集合数据时会按顺序
    10. Stream<Employee> stream = employees.stream();
    11. // default Stream parallelStream() : 返回一个并行流,类似于线程,无序
    12. Stream<Employee> parallelStream = employees.parallelStream();
    13. }
    14. //创建 Stream方式二:通过数组
    15. @Test
    16. public void test2(){
    17. int[] arr = new int[]{1,2,3,4,5,6};
    18. //调用Arrays类的static Stream stream(T[] array): 返回一个流
    19. IntStream stream = Arrays.stream(arr);
    20. Employee e1 = new Employee(1001,"Hom");
    21. Employee e2 = new Employee(1002,"Nut");
    22. Employee[] arr1 = new Employee[]{e1,e2};
    23. Stream<Employee> stream1 = Arrays.stream(arr1);
    24. }
    25. //创建 Stream方式三:通过Stream的of()
    26. @Test
    27. public void test3(){
    28. Stream<Integer> stream = Stream.of(1, 2, 3, 4, 5, 6);
    29. }
    30. //创建 Stream方式四:创建无限流
    31. @Test
    32. public void test4(){
    33. // 迭代
    34. // public static Stream iterate(final T seed, final UnaryOperator f)
    35. //遍历前10个偶数
    36. Stream.iterate(0, t -> t + 2).limit(10).forEach(System.out::println);
    37. // 生成
    38. // public static Stream generate(Supplier s)
    39. Stream.generate(Math::random).limit(10).forEach(System.out::println);
    40. }
    41. }

    Stream的中间操作:筛选与切片 

    方法描述
    filter(Predicate p)接收Lambda ,从流中排除某些元素
    distinct()筛选,通过流所生成元素的hashCode() 和equals() 去除重复元素
    limit(long maxSize)截断流,使其元素不超过给定数量
    skip(long n)跳过元素,返回一个扔掉了前n 个元素的流。若流中元素不足n 个,则返回一个空流。与limit(n)互补

     

    1. import org.junit.Test;
    2. import java.util.List;
    3. import java.util.stream.Stream;
    4. /**
    5. * 测试Stream的中间操作
    6. */
    7. public class StreamAPITest2 {
    8. //1-筛选与切片
    9. @Test
    10. public void test(){
    11. List list = EmployeeData.getEmployees();
    12. // filter(Predicate p)——接收 Lambda , 从流中排除某些元素。
    13. Stream stream = list.stream();
    14. //练习:查询员工表中薪资大于7000的员工信息
    15. stream.filter(e -> e.getSalary() > 7000).forEach(System.out::println);
    16. System.out.println("+++++++++++++++++++++++");
    17. // limit(n)——截断流,使其元素不超过给定数量。
    18. list.stream().limit(3).forEach(System.out::println);
    19. System.out.println("+++++++++++++++++++++++");
    20. // skip(n) —— 跳过元素,返回一个扔掉了前 n 个元素的流。若流中元素不足 n 个,则返回一个空流。与 limit(n) 互补
    21. list.stream().skip(3).forEach(System.out::println);
    22. System.out.println("+++++++++++++++++++++++");
    23. // distinct()——筛选,通过流所生成元素的 hashCode() 和 equals() 去除重复元素
    24. list.add(new Employee(1013,"李飞",42,8500));
    25. list.add(new Employee(1013,"李飞",41,8200));
    26. list.add(new Employee(1013,"李飞",28,6000));
    27. list.add(new Employee(1013,"李飞",39,7800));
    28. list.add(new Employee(1013,"李飞",40,8000));
    29. // System.out.println(list);
    30. list.stream().distinct().forEach(System.out::println);
    31. }
    32. }

    Stream的中间操作:映射 

    可以这么理解:filter是排除,map是提取

    1. import org.junit.Test;
    2. import java.util.ArrayList;
    3. import java.util.Arrays;
    4. import java.util.List;
    5. import java.util.stream.Stream;
    6. /**
    7. * 测试Stream的中间操作
    8. */
    9. public class StreamAPITest2 {
    10. //2-映射
    11. @Test
    12. public void test2(){
    13. // map(Function f)——接收一个函数作为参数,将元素转换成其他形式或提取信息,该函数会被应用到每个元素上,并将其映射成一个新的元素。
    14. List list = Arrays.asList("aa", "bb", "cc", "dd");
    15. list.stream().map(str -> str.toUpperCase()).forEach(System.out::println);
    16. // 练习1:获取员工姓名长度大于3的员工的姓名。
    17. List employees = EmployeeData.getEmployees();
    18. Stream namesStream = employees.stream().map(Employee::getName);
    19. namesStream.filter(name -> name.length() > 3).forEach(System.out::println);
    20. System.out.println();
    21. //练习2:
    22. Stream> streamStream = list.stream().map(StreamAPITest2::fromStringToStream);
    23. streamStream.forEach(s ->{
    24. s.forEach(System.out::println);
    25. });
    26. System.out.println("++++++++++++++++++++++");
    27. // flatMap(Function f)——接收一个函数作为参数,将流中的每个值都换成另一个流,然后把所有流连接成一个流。
    28. Stream characterStream = list.stream().flatMap(StreamAPITest2::fromStringToStream);
    29. characterStream.forEach(System.out::println);
    30. }
    31. //将字符串中的多个字符构成的集合转换为对应的Stream的实例
    32. public static Stream fromStringToStream(String str){//aa
    33. ArrayList list = new ArrayList<>();
    34. for(Character c : str.toCharArray()){
    35. list.add(c);
    36. }
    37. return list.stream();
    38. }
    39. @Test
    40. public void test3(){
    41. ArrayList list1 = new ArrayList();
    42. list1.add(25);
    43. list1.add(33);
    44. list1.add(14);
    45. ArrayList list2 = new ArrayList();
    46. list2.add(51);
    47. list2.add(23);
    48. list2.add(61);
    49. // list1.add(list2); 四个元素
    50. list1.addAll(list2); //这才是六个元素
    51. System.out.println(list1);
    52. }
    53. }

     Stream的中间操作:排序

    方法描述
    sorted()产生一个新流,其中按自然顺序排序
    sorted(Comparator com)产生一个新流,其中按比较器顺序排序
    1. import org.junit.Test;
    2. import java.util.ArrayList;
    3. import java.util.Arrays;
    4. import java.util.List;
    5. import java.util.stream.Stream;
    6. /**
    7. * 测试Stream的中间操作
    8. */
    9. public class StreamAPITest2 {
    10. //3-排序
    11. @Test
    12. public void test4(){
    13. // sorted()——自然排序
    14. List list = Arrays.asList(25,45,36,12,85,64,72,-95,4);
    15. list.stream().sorted().forEach(System.out::println);
    16. //抛异常,原因:Employee没有实现Comparable接口,对象排序必须去实现Comparable接口
    17. // List employees = EmployeeData.getEmployees();
    18. // employees.stream().sorted().forEach(System.out::println);
    19. // sorted(Comparator com)——定制排序
    20. List employees = EmployeeData.getEmployees();
    21. employees.stream().sorted( (e1,e2) -> {
    22. int ageValue = Integer.compare(e1.getAge(),e2.getAge());
    23. if(ageValue != 0){
    24. return ageValue;
    25. }else{
    26. return -Double.compare(e1.getSalary(),e2.getSalary());
    27. }
    28. }).forEach(System.out::println);
    29. }
    30. }

    Stream的终止操作:匹配与查找

    • 终端操作会从流的流水线生成结果。其结果可以是任何不是流的值,例如:List、Integer,甚至是void 。
    • 流进行了终止操作后,不能再次使用。
    方法描述
    allMatch(Predicate p)检查是否匹配所有元素
    anyMatch(Predicate p)检查是否至少匹配一个元素
    noneMatch(Predicate p)检查是否没有匹配所有元素
    findFirst()返回第一个元素
    findAny()返回当前流中的任意元素
    count()返回流中元素总数
    max(Comparator c)返回流中最大值
    min(Comparator c)返回流中最小值
    forEach(Consumer c)内部迭代(使用Collection 接口需要用户去做迭代,称为外部迭代。相反,Stream API 使用内部迭代——它帮你把迭代做了)
    1. import org.junit.Test;
    2. import java.util.List;
    3. import java.util.Optional;
    4. import java.util.stream.Stream;
    5. public class StreamAPITest3 {
    6. //1-匹配与查找
    7. @Test
    8. public void test(){
    9. List employees = EmployeeData.getEmployees();
    10. // allMatch(Predicate p)——检查是否匹配所有元素。
    11. // 练习:是否所有的员工的年龄都大于18
    12. boolean allMatch = employees.stream().allMatch(e -> e.getAge() > 23);
    13. System.out.println(allMatch);
    14. // anyMatch(Predicate p)——检查是否至少匹配一个元素。
    15. // 练习:是否存在员工的工资大于 10000
    16. boolean anyMatch = employees.stream().anyMatch(e -> e.getSalary() > 9000);
    17. System.out.println(anyMatch);
    18. // noneMatch(Predicate p)——检查是否没有匹配的元素。
    19. // 练习:是否存在员工姓“马”
    20. boolean noneMatch = employees.stream().noneMatch(e -> e.getName().startsWith("马"));
    21. System.out.println(noneMatch);
    22. // findFirst——返回第一个元素
    23. Optional employee = employees.stream().findFirst();
    24. System.out.println(employee);
    25. // findAny——返回当前流中的任意元素
    26. Optional employee1 = employees.parallelStream().findAny();
    27. System.out.println(employee1);
    28. }
    29. @Test
    30. public void test2(){
    31. List employees = EmployeeData.getEmployees();
    32. // count——返回流中元素的总个数
    33. long count = employees.stream().filter(e -> e.getSalary() > 4500).count();
    34. System.out.println(count);
    35. // max(Comparator c)——返回流中最大值
    36. // 练习:返回最高的工资:
    37. Stream salaryStream = employees.stream().map(e -> e.getSalary());
    38. Optional maxSalary = salaryStream.max(Double::compare);
    39. System.out.println(maxSalary);
    40. // min(Comparator c)——返回流中最小值
    41. // 练习:返回最低工资的员工
    42. Optional employee = employees.stream().min((e1, e2) -> Double.compare(e1.getSalary(), e2.getSalary()));
    43. System.out.println(employee);
    44. System.out.println();
    45. // forEach(Consumer c)——内部迭代
    46. employees.stream().forEach(System.out::println);
    47. //使用集合的遍历操作
    48. employees.forEach(System.out::println);
    49. }
    50. }

    Stream的终止操作:归约

    方法描述
    reduce(T iden, BinaryOperator b)可以将流中元素反复结合起来,得到一个值。返回T
    reduce(BinaryOperator b)可以将流中元素反复结合起来,得到一个值。返回Optional

    备注:map 和reduce 的连接通常称为map-reduce 模式,因Google 用它来进行网络搜索而出名。

    1. import github2.Employee;
    2. import github2.EmployeeData;
    3. import org.junit.Test;
    4. import java.util.Arrays;
    5. import java.util.List;
    6. import java.util.Optional;
    7. import java.util.stream.Stream;
    8. public class StreamAPITest3 {
    9. //2-归约
    10. @Test
    11. public void test3(){
    12. // reduce(T identity, BinaryOperator)——可以将流中元素反复结合起来,得到一个值。返回 T
    13. // 练习1:计算1-10的自然数的和
    14. List list = Arrays.asList(72,25,32,34,43,56,81,15,29,71);
    15. Integer sum = list.stream().reduce(0, Integer::sum);
    16. System.out.println(sum);
    17. // reduce(BinaryOperator) ——可以将流中元素反复结合起来,得到一个值。返回 Optional
    18. // 练习2:计算公司所有员工工资的总和
    19. List employees = EmployeeData.getEmployees();
    20. Stream salaryStream = employees.stream().map(Employee::getSalary);
    21. // Optional sumMoney = salaryStream.reduce(Double::sum);
    22. Optional sumMoney = salaryStream.reduce((d1,d2) -> d1 + d2);
    23. System.out.println(sumMoney.get());
    24. }
    25. }

    Stream的终止操作:收集

    方法描述
    collect(Collector c)将流转换为其他形式。接收一个Collector接口的实现,用于给Stream中元素做汇总的方法

     

    1. import org.junit.Test;
    2. import java.util.Arrays;
    3. import java.util.List;
    4. import java.util.Optional;
    5. import java.util.Set;
    6. import java.util.stream.Collectors;
    7. import java.util.stream.Stream;
    8. public class StreamAPITest3 {
    9. //3-收集
    10. @Test
    11. public void test4() {
    12. // collect(Collector c)——将流转换为其他形式。接收一个 Collector接口的实现,用于给Stream中元素做汇总的方法
    13. // 练习1:查找工资大于6000的员工,结果返回为一个List或Set
    14. List employees = EmployeeData.getEmployees();
    15. List employeeList = employees.stream().filter(e -> e.getSalary() > 6000).collect(Collectors.toList());
    16. employeeList.forEach(System.out::println);
    17. System.out.println("++++++++++++++++++");
    18. Set employeeSet = employees.stream().filter(e -> e.getSalary() > 6000).collect(Collectors.toSet());
    19. employeeSet.forEach(System.out::println);
    20. }
    21. }

     

    Collector 接口中方法的实现决定了如何对流执行收集的操作(如收集到List、Set、Map)。

    Collectors实用类提供了很多静态方法,可以方便地创建常见收集器实例,具体方法与实例如下表:

    3.Optional类

    到目前为止,臭名昭著的空指针异常是导致Java应用程序失败的最常见原因。以前,为了解决空指针异常,Google公司著名的Guava项目引入了Optional类,Guava通过使用检查空值的方式来防止代码污染,它鼓励程序员写更干净的代码。受到Google Guava的启发,Optional类已经成为Java 8类库的一部分。

    • Optional 类(java.util.Optional) 是一个容器类,它可以保存类型T的值,代表这个值存在。或者仅仅保存null,表示这个值不存在。原来用null 表示一个值不存在,现在Optional 可以更好的表达这个概念。并且可以避免空指针异常
    • Optional类的Javadoc描述如下:这是一个可以为null的容器对象。如果值存在则isPresent()方法会返回true,调用get()方法会返回该对象。
    • Optional提供很多有用的方法,这样我们就不用显式进行空值检测。
    • 创建Optional类对象的方法:

                 

    • Optional.of(T t): 创建一个Optional 实例,t必须非空;
    • Optional.empty() : 创建一个空的Optional 实例
    • Optional.ofNullable(T t):t可以为null
    • 判断Optional容器中是否包含对象:
      • boolean isPresent() : 判断是否包含对象
      • void ifPresent(Consumer consumer) :如果有值,就执行Consumer接口的实现代码,并且该值会作为参数传给它。

    获取Optional容器的对象:

    • T get(): 如果调用对象包含值,返回该值,否则抛异常
    • T orElse(T other) :如果有值则将其返回,否则返回指定的other对象。
    • T orElseGet(Supplier other) :如果有值则将其返回,否则返回由Supplier接口实现提供的对象。
    • T orElseThrow(Supplier exceptionSupplier) :如果有值则将其返回,否则抛由Supplier接口实现提供的异常。
       

     Boy.class

    1. public class Boy {
    2. private Girl girl;
    3. public Boy() {
    4. }
    5. public Boy(Girl girl) {
    6. this.girl = girl;
    7. }
    8. public Girl getGirl() {
    9. return girl;
    10. }
    11. public void setGirl(Girl girl) {
    12. this.girl = girl;
    13. }
    14. @Override
    15. public String toString() {
    16. return "Boy{" +
    17. "girl=" + girl +
    18. '}';
    19. }
    20. }

     Girl.class

    1. public class Girl {
    2. private String name;
    3. public Girl() {
    4. }
    5. public Girl(String name) {
    6. this.name = name;
    7. }
    8. public String getName() {
    9. return name;
    10. }
    11. public void setName(String name) {
    12. this.name = name;
    13. }
    14. @Override
    15. public String toString() {
    16. return "Girl{" +
    17. "name='" + name + '\'' +
    18. '}';
    19. }
    20. }

     测试类

    1. import org.junit.Test;
    2. import java.util.Optional;
    3. /**
    4. * Optional类:为了在程序中避免出现空指针异常而创建的。
    5. *
    6. * 常用的方法:ofNullable(T t)
    7. * orElse(T t)
    8. */
    9. public class OptionalTest {
    10. /**
    11. * Optional.of(T t) : 创建一个 Optional 实例,t必须非空;
    12. * Optional.empty() : 创建一个空的 Optional 实例
    13. * Optional.ofNullable(T t):t可以为null
    14. */
    15. @Test
    16. public void test(){
    17. Girl girl = new Girl();
    18. // girl = null;
    19. //of(T t):保证t是非空的,如t为空,会报空指针异常
    20. Optional optionalGirl = Optional.of(girl);
    21. }
    22. @Test
    23. public void test2(){
    24. Girl girl = new Girl();
    25. // girl = null;
    26. //ofNullable(T t):t可以为null,如果为空,会返回Optional.empty()
    27. Optional optionalGirl = Optional.ofNullable(girl);
    28. System.out.println(optionalGirl);
    29. //orElse(T t1):如果单前的Optional内部封装的t是非空的,则返回内部的t.
    30. //如果内部的t是空的,则返回orElse()方法中的参数t1.
    31. Girl girl1 = optionalGirl.orElse(new Girl(""));
    32. System.out.println(girl1);
    33. }
    34. }

    应用场景

    1. import org.junit.Test;
    2. import java.util.Optional;
    3. /**
    4. * Optional类:为了在程序中避免出现空指针异常而创建的。
    5. *
    6. * 常用的方法:ofNullable(T t)
    7. * orElse(T t)
    8. */
    9. public class OptionalTest {
    10. @Test
    11. public void test3(){
    12. Boy boy = new Boy();
    13. boy = null;
    14. String girlName = getGirlName(boy);
    15. System.out.println(girlName);
    16. }
    17. private String getGirlName(Boy boy) {
    18. return boy.getGirl().getName();
    19. }
    20. //优化以后的getGirlName():
    21. public String getGirlName1(Boy boy){
    22. if(boy != null){
    23. Girl girl = boy.getGirl();
    24. if(girl != null){
    25. return girl.getName();
    26. }
    27. }
    28. return null;
    29. }
    30. @Test
    31. public void test4(){
    32. Boy boy = new Boy();
    33. boy = null;
    34. String girlName = getGirlName1(boy);
    35. System.out.println(girlName);
    36. }
    37. //使用Optional类的getGirlName():
    38. public String getGirlName2(Boy boy){
    39. Optional boyOptional = Optional.ofNullable(boy);
    40. //此时的boy1一定非空
    41. Boy boy1 = boyOptional.orElse(new Boy(new Girl("朱淑贞")));
    42. Girl girl = boy1.getGirl();
    43. Optional girlOptional = Optional.ofNullable(girl);
    44. //girl1一定非空
    45. Girl girl1 = girlOptional.orElse(new Girl("阿青"));
    46. return girl1.getName();
    47. }
    48. @Test
    49. public void test5(){
    50. Boy boy = null;
    51. boy = new Boy();
    52. boy = new Boy(new Girl("李清照"));
    53. String girlName = getGirlName2(boy);
    54. System.out.println(girlName);
    55. }
    56. }

     总结:Optional就是把null当成了一个合法对象了,以前我们会用if语句来判空,现在可以用Optional中的orElse方法可以作为一个备用方法来考虑为空的情景并返回,就可以规避了空指针的问题。

     

  • 相关阅读:
    javaweb第一章 mysql数据库
    【Mquant】7:构建价差套利(三) ——空间误差校正模型
    分类预测 | Matlab实现基于LFDA-SVM局部费歇尔判别数据降维结合支持向量机的多输入分类预测
    【期末网页设计】基于HTML学生信息管理系统网页项目的设计与实现
    从阿里云OSS迁移到AWS S3的步骤
    03路由策略
    vue总结(一)
    java计算机毕业设计足球赛会管理系统源程序+mysql+系统+lw文档+远程调试
    基于人体呼出气体的电子鼻系统的设计与实现
    html2canvs的一些问题
  • 原文地址:https://blog.csdn.net/m0_46845579/article/details/126047904