JavaBase-Java8新特性

JavaBase-Java8新特性

简介

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

并行流与串行流

  • 并行流就是把一个内容分成多个数据块,并用不同的线程分别处理每个数据块的流。相比串行流,并行流可以很大程度上提高程序的执行效率
  • Java8中将并行进行优化骂我们可以很容易的对数据进行并行操作。
  • StreamAPI可以声明性地通过parallel()与sequential()在并行流与顺序流之间进行切换

Lambda表达式

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

  • public static void main(String[] args) {
        Thread t1 = new Thread(() -> System.out.println("dfasfsd"));
        t1.start();
        Comparator<Integer>  c = Integer::compareTo;
        System.out.println(c.compare(1, 2));
    }
    

Lambda表达式的使用

  • 举例:(o1,o2) -> Integer.compareTo(o1,o2);

  • 格式:

    • ->:lambda表达式 或 箭头操作符
    • ->左边:lambda形参列表(其实就是接口中的抽象方法中的形参列表)
    • ->右边:lambda体(其实就是重写的抽象方法的方法体)
  • Lambda表达式的使用:(分6种情况)

    • 语法格式一:无参,无返回值

      • Runnable runnable = () -> System.out.println("你好");
        
    • 语法格式二:Lambda了需要一个参数,但是没有返回值

      • Consumer<String> con = (String str) -> System.out.println(str);
        
    • 语法格式三:数据类型可以省略,因为可由编译期判断得出,称为“类型判断”

      • Consumer<String> con = (str) -> System.out.println(str);
        
    • 语法格式四:Lambda若只需要一个参数,参数的小括号可以省略

      • Consumer<String> con = str -> System.out.println(str);
        
    • 语法格式五:Lambda需要两个或以上的参数,多条执行语句,并且可以有返回值

      • Comparator<Integer> com = (x,y) -> {
            return Integer.compare(x,y)
        };
        
    • 语法格式六:当Lambda体只有一条语句时,return与大括号若有,都可以省略

      • Comparator<Integer> com2 = (x,y) ->  Integer.compare(x,y);;
        
  • Lambda表达式的本质:作为接口的实例

  • Lambda表达式总结:

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

函数式(Functional)接口

  • 只包含一个抽象方法的接口,称为函数式接口
  • 可以通过Lambda表达式来创建该接口的对象。(若Lambda表达式抛出一个受检异常(即:非运行异常),那么该异常需要在目标接口的抽象方法上进行声明)。
  • 我们可以在一个接口上使用@FunctionalInterface注解,这样做可以检查它是否是一个函数式接口。同时javadoc也会包含一条声明,说明这个接口是一个函数式接口

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

函数式接口参数类型返回类型用途
Consumer消费型jiekouTvoid对类型为T的对象应用操作,包含方法,void accept(T t)
Supplier供给型接口T返回类型为T的对象,包含方法:T get()
Function<T,R>函数型接口TR对类型为T的对象应用操作,并返回结果。结果是R类型的对象。包含方法:R apply(T t)
Predicate断定型接口Tboolean确定类型为T的对象是否满足某约束,并返回boolean值。包含方法:boolean test(T t)

例子:

  • Consumer

    • Consumer<String> consumer = (t)-> System.out.println(t);
      consumer.accept("dfasdf");
      
  • Supplier

    • Supplier<String> supplier = () -> "dfasfdas";
      System.out.println(supplier.get());
      
  • Function<T,R>

    • Function<String,Integer> function = (s)->{
          System.out.println(s);
          return 1;
      };
      System.out.println(function.apply("Dfadf"));
      
  • Predicate

    • Predicate<String> predicate = (x) -> x.compareTo("t") > -1;
      System.out.println(predicate.test("dasfd"));
      

方法引用与构造器引用

方法引用

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

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

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

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

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

    • 对象::实例方法名

      • /**
         * 情况1:对象 :: 实例方法
         * Consumer中的 void accept(T t);
         * PrintStream中的 void println(T t);
         */
        @Test
        public void test1(){
            Consumer<String> consumer1 = str -> System.out.println(str);
            consumer1.accept("你好");
            System.out.println("*************************");
            Consumer<String> consumer2 = System.out :: println;
            consumer2.accept("你好2");
            
        }
        
    • 类::静态方法名

      • /** * 情况2: 类 :: 静态方法 * */@Testpublic void test2(){    Comparator<Integer> comparator1 = (t1,t2)->Integer.compare(t1,t2);    comparator1.compare(1,2);    System.out.println("***********************");    Comparator<Integer> comparator2 = Integer ::compare;    comparator2.compare(1,2);}
        
    • 类::实例方法名

      • /**
         * 情况三:类 :: 实例方法
         * Comparator中的int compare(T t1,T t2)
         * String中的int t1.compareTo(t2)
         */
        @Test
        public void test5(){
            Comparator<String> comparator1 = (s1,s2) -> s1.compareTo(s2);
            Comparator<String> comparator = String :: compareTo;
        
            BiPredicate<String,String> biPredicate = (t1,t2) -> t1.equals(t2);
            System.out.println(biPredicate.test("A", "A"));
            System.out.println("************************");
        
            BiPredicate<String,String> biPredicate1 = String :: equals;
            System.out.println(biPredicate1.test("B", "B"));
        }
        
  • 使用情境:当腰传递给Lambda体的操作,已经有实现的方法了,可以使用方法引用!

  • 方法引用,本质上就是Lambda表达式,而Lambda表达式作为函数式接口的实例。所以方法引用,也是函数式接口的实例

  • //类 :: 静态方法名
    Comparator<Integer>  c = Integer::compareTo;
    System.out.println(c.compare(1, 2));
    //对象 :: 实例方法名
    Supplier<Integer> supplier = new Integer(1) :: intValue;
    //类 :: 实例方法名
    Function<Integer, Integer> integerIntegerFunction = Integer::intValue;
    

构造器引用

  • 和方法引用类似,函数接口的抽象方法和形参列表和构造器的形参列表一致

  • 抽象方法的返回值类型即为构造器所属的类的类型

    • public class Employee {
      
          private int id;
          private String name;
          private int age;
          private Double salary;
      
          public Employee(int id) {
              this.id = id;
          }
      }
      /**
       * 构造器引用
       */
      @Test
      public void test6(){
          Function<Integer, Employee> integerEmployeeFunction = Employee::new;
          System.out.println(integerEmployeeFunction.apply(1));
      }
      

数组引用

可以把数组看作是一个特殊的类,则写法与构造器一样

/** * 数组引用 */@Testpublic void test7(){    Function<Integer,String[]> function = length -> new String[length];    System.out.println(function.apply(1));    System.out.println("*********************");    Function<Integer,String[]> function1 = String[] :: new;    System.out.println(function1.apply(9));}

强大的StreamAPI

概念

  • Java8中有两个最为重要的改变。第一个是Lambda表达式;另一个则是Stream API;
  • Stream API(java.util.stream)把真正的函数式编程风格引入到Java中。这是目前为止对Java类库最好的补充,因为Stream API可以极大提供Java程序员的生产力,让程序员写出高效率、干净、简洁的代码。
  • Stream是Java8中处理集合的关键抽象概念,它可以指定希望对集合进行的操作,可以执行非常复杂的查找、过滤和映射数据等操作。使用Sream API对集合数据进行操作,就类似于使用SQL执行的数据库查询。也可以使用Stream API来并行执行操作。简而言之,Stream API提供了一种高效而易于使用的处理数据的方式
为什么要使用Stream API
  • 实际开发中,项目中多数数据源都来自于MySql,Oracle等。但现在数据源可以更多了,有MongDB,Redis等,而这些NoSQL的数据就需要Java层面去处理。
  • Collection集合和Stream的区别:Collection是一种静态的内存数据结构,而Stream是有关计算的。前者主要面向内存,存储在内存中,后者主要面向CPU,通过CPU实现计算。
什么是Stream API
  • Stream到底是什么?
    • 是数据渠道,用于操作数据源(集合、数组等)所生成的元素序列。
    • “集合讲的是数据,Stream讲的是计算“
  • 注意
    • Stream自己不会存储元素
    • Stream不会改变源对象。相反,他们会返回一个持有结果的Stream。
    • Stream操作是延迟执行的。这意味着他们会等到需要结果的时候才执行。

Stream的操作三个步骤

  • 1-创建Stream
    • 一个数据源(如:集合、数组),获取一个流
  • 2-中间操作
    • 一个中间操作链,对数据源的数据进行处理
  • 3-终止操作
    • 一旦执行终止操作,就执行中间操作链,并产生结果。之后,不会再被使用
  • 在这里插入图片描述
创建Stream方式
  • 创建Stream方式一:通过集合

    • Java8的Collection接口被扩展,提供了两个获取流的方法:

      • default Stream stream(): 返回一个顺序流
      • default Stream parallelStream():返回一个并行流
    • /**
       * 创建Stream方式一:通过集合
       */
      @Test
      public void test1(){
          List<Employee> employees = EmployeeData.getEmployees();
          //default Stream<E> stream():返回一个顺序流
          Stream<Employee> stream = employees.stream();
          //default Stream<E> parallelStream():返回一个并行流
          Stream<Employee> employeeStream = employees.parallelStream();
      }
      
  • 创建Stream方式二:通过数组

    • Java8中Arrays的静态方法stream()可以获取数组流:

      • static Stream stream(T[] arrays):返回一个流
      • 重载形式,能够处理对应基本数据类型的数组:
        • public static IntStream stream(int[] array)
        • public static LongStream stream(long[] array)
        • public static DoubleStream stream(double[] array)
    • /**
       * 创建Stream方式二:通过数组
       */
      @Test
      public void test2(){
          int[] ints = new int[]{1,2,3};
          IntStream stream = Arrays.stream(ints);
          
          Employee[] employees = new Employee[]{new Employee(1,"2",1,21.0)};
          Stream<Employee> stream1 = Arrays.stream(employees);
      }
      
  • 创建Stream方式三:通过Stream的of()

    • 可以调用Stream类静态方法of(),通过显示值创建一个流。它可以接受任意数量的参数。

      • public static Stream of(T… values):返回一个流

      • /**
         * 创建Stream方式三:通过Stream的of()
         */
        @Test
        public void test3(){
            Stream<Integer> integerStream = Stream.of(1, 2, 3);
        }
        
  • 创建Stream方式四:创建无限流

    • 可以使用静态方法Stream.iterate()和Stream.generate(),创建无限流。

      • 迭代
        • public static Stream iterate(final T seed,final UnaryOperator f)
      • 生成
        • public static Stream generate(Supplier s)
    • /**
       * 创建Stream方式四:创建无限流
       */
      @Test
      public void test4(){
          //迭代
          //public static<T> Stream<T> iterate(final T seed,final UnaryOperator<T> f)
          Stream.iterate(new Employee(1,"dfsf",1,23.0), (t)->{
              return new Employee(t.getId()+1);
          }).limit(10).forEach(System.out::println);
      
          //生成
          //public static<T> Stream<T> generate(Supplier<T> s)
          Random random = new Random();
          Stream.generate(()-> random.nextInt(10)).limit(10).forEach(System.out::println);
      }
      
Stream的中间操作
  • 多个中间操作可以连接起来形成一个流水线,除非流水线上触发终止操作,否则中间操作不会执行任何的处理!而在终止操作时一次性全部处理,称为“惰性求值”

  • 1-筛选与切片

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

      • @Test
        public void test6(){
            //distinct()   筛选,通过流所生成元素的hashCode()和equals去除重复元素
            EmployeeData.getEmployees().stream().distinct().forEach(System.out::println);
        }
        
        
        @Test
        public void test7(){
            EmployeeData.getEmployees().stream().forEach(System.out::println);
            System.out.println("********************");
            //limit(long maxSize)  截断流,使其元素不超过给定数量
            EmployeeData.getEmployees().stream().limit(2).forEach(System.out::println);
        
        }
        
        
        @Test
        public void test8(){
            EmployeeData.getEmployees().stream().forEach(System.out::println);
            System.out.println("********************");
            //skip(long n) 跳过元素,返回一个扔掉了前n个元素的流。若流中元素不足n个,则返回一个空流。与limit(n)互补
            EmployeeData.getEmployees().stream().skip(2).forEach(System.out::println);
        
        }
        
  • 2-映射

    • 方法描述
      map(Function f)接收一个函数作为参数,该函数会被应用到每个元素上,并将其映射成一个新的元素
      mapToDouble(ToDoubleFuncion f)接收一个函数作为参数,该函数会被应用到每个元素上,产生一个新的DoubleStream。
      mapToInt(ToIntFunction f)接收一个函数作为参数,该函数会被应用到每个元素上,产生一个新的IntStream。
      mapToLong(ToLongFunction f)接收一个函数作为参数,该函数会被应用到每个元素上,产生一个新的LongStream。
      flatMap(Function f)接收一个函数作为参数,将流中的每个值都换成另一个流,然后把所有流连接成一个流
    • 代码例子

      • @Test
        public void test1(){
            //map(Function f)  接收一个函数作为参数,该函数会被应用到每个元素上,并将其映射成一个新的元素
            EmployeeData.getEmployees().stream().map((e)->{
                e.setId(e.getId()+1000);
                return e;
            }).forEach(System.out::println);
            System.out.println("********************");
            EmployeeData.getEmployees().stream()
                    .filter((e)->e.getName().length()>3).map(Employee::getName).forEach(System.out::println);
        }
        
        @Test
        public void test2(){
            //mapToDouble(ToDoubleFuncion f)   接收一个函数作为参数,该函数会被应用到每个元素上,产生一个新的DoubleStream。
            EmployeeData.getEmployees().stream().mapToDouble((e)->e.getSalary()).forEach(System.out::println);
        }
        
        
        @Test
        public void test3(){
            //mapToInt(ToIntFunction f)    接收一个函数作为参数,该函数会被应用到每个元素上,产生一个新的IntStream。
            EmployeeData.getEmployees().stream().mapToInt((e)->e.getId()).forEach(System.out::println);
        }
        
        @Test
        public void test4(){
            //mapToLong(ToLongFunction f)  接收一个函数作为参数,该函数会被应用到每个元素上,产生一个新的LongStream。
            EmployeeData.getEmployees().stream().mapToLong((e)->e.getAge()).forEach(System.out::println);
        }
        
        @Test
        public void test5(){
            //flatMap(Function f)  接收一个函数作为参数,将流中的每个值都换成另一个流,然后把所有流连接成一个流
            EmployeeData.getEmployees().stream().forEach(System.out::println);
            System.out.println("*****************");
            EmployeeData.getEmployees().stream().flatMap((e)-> Arrays.asList(e).stream()).forEach(System.out::println);
        }
        
        @Test
        public void test6(){
            List<String> list = Arrays.asList("aa","BB","CC","DD");
            Stream<Stream<Character>> streamStream = list.stream().map(StreamAPITest2::fromStringToStream);
            streamStream.forEach((i)->{
                i.forEach(System.out::println);
            });
            System.out.println("***********************");
            Stream<Character> characterStream = list.stream().flatMap(StreamAPITest2::fromStringToStream);
            characterStream.forEach(System.out::println);
        }
        
        @Test
        public void test7(){
            List<String> list = Arrays.asList("aa","BB","CC","DD");
            Stream<ArrayList<Character>> arrayListStream = list.stream().map(StreamAPITest2::fromStringToStream2);
            arrayListStream.forEach(System.out::println);
            System.out.println("***********************");
            Stream<Character> characterStream = list.stream().flatMap((s) -> StreamAPITest2.fromStringToStream2(s).stream());
            characterStream.forEach(System.out::println);
            System.out.println("***********************");
            Stream<Stream<Character>> streamStream = list.stream().map((s) -> StreamAPITest2.fromStringToStream2(s).stream());
            streamStream.forEach(System.out::println);
        }
        
        private static Stream<Character> fromStringToStream(String str) {
            ArrayList<Character> list = new ArrayList<>();
            for(Character c : str.toCharArray()){
                list.add(c);
            }
            return list.stream();
        }
        
        private static ArrayList<Character> fromStringToStream2(String str) {
            ArrayList<Character> list = new ArrayList<>();
            for(Character c : str.toCharArray()){
                list.add(c);
            }
            return list;
        }
        
  • 3-排序

    • 方法描述
      sorted()产生一个新流,其中按自然顺序排序
      sorted(Comparator com)产生一个新流,其中按比较器定制排序顺序排序
    • 代码

      • @Test
        public void test1(){
            //sorted() 产生一个新流,其中按自然顺序排序
            EmployeeData.getEmployees().stream().sorted().forEach(System.out::println);
        }
        
        @Test
        public void test2(){
            //sorted(Comparator com)   产生一个新流,其中按比较器定制排序顺序排序
            EmployeeData.getEmployees().stream().sorted((e1,e2)->{
                return Integer.compare(e1.getAge(),e2.getAge());
            }).forEach(System.out::println);
        
            System.out.println("***************");
        
            EmployeeData.getEmployees().stream().sorted(Comparator.comparingInt(Employee::getAge)).forEach(System.out::println);
        }
        
Stream的终止操作
  • 终止操作会从流的流水线生成结果。其结果可以是任何不是流的值,例如:List、Integer,甚至是void。

  • 流进行了终止操作后,不能再次使用。

    • 1-匹配与查找

      • 方法描述
        allMatch(Predicate p)检查是否匹配所有元素
        anyMatch(Predicate p)检查是否至少匹配一个元素
        noneMatch(Predicate p)检查是否没有匹配所有元素
        findFirst()返回第一个元素
        findAny()返回当前流中的任意元素
        count()返回流中元素总数
        max(Comparator c)返回流中最大值
        min(Comparator c)返回流中最小值
        forEach(Consumer c)内部迭代(使用Collection接口需要用户去做迭代,称为外部迭代。相反,Stream API使用内部迭代—它帮忙把迭代做了
    • 代码

      •     @Test
            public void test1(){
        //        allMatch(Predicate p)    检查是否匹配所有元素
        
                System.out.println(EmployeeData.getEmployees().stream().allMatch(employee -> employee.getSalary() > 2000));
            }
        
        
            @Test
            public void test2(){
        //        anyMatch(Predicate p)    检查是否至少匹配一个元素
                System.out.println(EmployeeData.getEmployees().stream().anyMatch(employee -> employee.getSalary() > 2000));
            }
        
            @Test
            public void test3(){
        //        noneMatch(Predicate p)   检查是否没有匹配所有元素
                System.out.println(EmployeeData.getEmployees().stream().noneMatch(employee -> employee.getSalary() < 0));
            }
        
            @Test
            public void test4(){
        //        noneMatch(Predicate p)   检查是否没有匹配所有元素
                System.out.println(EmployeeData.getEmployees().stream().findFirst());
            }
        
            @Test
            public void test5(){
        //        findAny()    返回当前流中的任意元素
                System.out.println(EmployeeData.getEmployees().stream().findAny());
            }
        
            @Test
            public void test6(){
        //        count()	返回流中元素总数
               System.out.println(EmployeeData.getEmployees().stream().count());
            }
        
            @Test
            public void test7(){
        //        max(Comparator c)	返回流中最大值
                //返回年龄最大的对象 如果出现两个对象,返回的是先被找到的对象
                System.out.println(EmployeeData.getEmployees().stream()
                        .max(Comparator.comparingInt(Employee::getAge)));
            }
        
            @Test
            public void test8(){
        //        max(Comparator c)	返回流中最大值
                //返回年龄最小的对象 如果出现两个对象,返回的是先被找到的对象
                System.out.println(EmployeeData.getEmployees().stream()
                        .min(Comparator.comparingInt(Employee::getAge)));
            }
        
            @Test
            public void test9(){
                //        forEach(Consumer c)	内部迭代(使用Collection接口需要用户去做迭代,称为外部迭代。相反,Stream API使用内部迭代---它帮忙把迭代做了
                EmployeeData.getEmployees().stream().forEach((e)->{
                    e.getSalary();
                    System.out.println(e.getSalary()+1);
                });
            }
        
  • 2-归约

    • 备注:

      • Map和reduce的连接通常称为map-reduce的连接通常称为map-reduce模式,因Google用它来进行网络搜索而名
    • 方法描述
      reduce(T iden,BinaryOperator b)可以将流中元素反复结合起来,得到一个值。返回T
      reduce(BinaryOperator b)可以将流中元素反复结合起来,得到一个值。返回Optional
    • 代码例子

      • @Test
        public void test10(){
            //reduce(T iden,BinaryOperator b)  可以将流中元素反复结合起来,得到一个值。返回T
            //练习1 : 计算1-10的自然数的和
            List<Integer> list = Arrays.asList(1,2,3,4,5,6,7,8,9,10);
            Integer reduce1 = list.stream().reduce(0, (t1, t2) -> {
                return t1 + t2;
            });
            System.out.println(reduce1);
        
            //reduce(BinaryOperator b) 可以将流中元素反复结合起来,得到一个值。返回Optional<T>
            //练习2:计算所有员工工资总和
            OptionalDouble reduce = EmployeeData.getEmployees().stream()
                    .mapToDouble(Employee::getSalary).reduce(Double::sum);
            System.out.println(reduce.getAsDouble());
        }
        
  • 3-收集

    • 备注

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

      • 另外,Collectors使用类提供了很多静态方法,可以方便地创建常见收集齐实例,

        • 方法返回类型作用
          toListList把流中元素收集到List
          List list = list.stream().collect(Collectors.toList());
          toSetSet把流中元素收集到Set
          Set set = list.stream().collect(Collectors.toSet());
          toCollectionCollection把流中的元素收集到创建的集合
          Collection emps = list.stream().collect(Collectors.toCollection(ArrayList::new))l
          countingLong计算流中元素的个数
          long count = list.stream().collect(Collectors.counting());
          summingIntInteger对流中元素的整数属性求和
          int total=list.stream().collect(Collectors.summingInt(Employee::getSalary));
          averageingIntDouble计算流中元素Integer属性的平均值
          double avg = list.stream().collect(Collectors.averagingInt(Employee::getSalary));
          summrizingIntIntSummaryStatistics收集流中Integer属性的统计值。如:平均值
          int SummaryStatisticsiss = list.stream().collect(Collectors.summarizingInt(Employee::getSalary));
          joiningString连接流中每个字符串
          String str =list.stream().map(Employee::getName).collect(Collectors.joining));
          maxByOptional根据比较器选择最大值
          Optional max = list.stream().collect(Collectors.maxBy(comparingInt(Employee::getSalary));
          minByOptional根据比较器选择最小值
          Optional min = list.stream().collect(Collectors.minBy(comparingInt(Employee::getSalary));
          reducing归约产生的类型从一个作为累加器的初始值开始,利用BinaryOperator与流中元素逐个结合,从未归约成单个值
          int total=list.stream().collect(Collectors.reducing(0,Employee::getSalary,Integer::sum));
          collectingAndThen转换函数返回的类型包裹另一个收集齐,对其结果转换函数
          int how = list.stream().collect(Collectors.collectingAndThen(Collectors.toList(),List::size)
          groupingByMap<K,List>根据某属性值对流分组,属性为K,结果为V
          Map<Emp.Status,List> map = list.stream().collect(Collectors.groupingBy(Employee::getStatus));
          partitioningByMap<Boolean,List>根据true或false进行分区
          Map<Boolean,List> vd = list.stream().collect(Collectors.partitioningBy(Employee::getManage));
    • 方法描述
      collect(Collector c)将流转换为其他形式。接收一个Collector接口的实现,用于给Stream中元素做汇总的方法

Optional类

概念

  • 到目前为止,臭名昭著的空指针异常是导致Java应用程序失败的最常见的原因。以前,为了解决空指针异常,Google公司著名的Guava项目引入了Optional类,Guava通过使用检查空值的方式来防止代码污染,它鼓励程序员更干净的代码。受到Google Guava的启发,Optional类已经成为Java 8 类库的一部分
  • Optional类(java.util.Optional)是一个容器来,它可以保存类型T的值,代表这个值存在。或者仅仅保存null,表示这个值不存在。原来用null表示一个值不存在,现在Optional可以更好的表达这个概念。并且可以避免空指针异常。
  • Optional类的javac描述如下:这是一个可以为null的容器对象。如果值存在则isPresent()方法会返回true,则调用get()方法会返回对象

Optional类的方法

  • Optional类提供很多有用的方法,这样我们就不用显式进行空值检测。

  • 创建Optional类对象的方法:

    • Optional.of(T t):创建一个Optional实例,t必须非空;

    • Optional.empty():创建一个空的Optional实例

    • Optional.ofNullable(T t):t可以为null

    • /**
       * - Optional.of(T t):创建一个Optional实例,t必须非空;
       * - Optional.empty():创建一个空的Optional实例
       * - Optional.ofNullable(T t):t可以为null
       */
      @Test
      public void test(){
          Optional<Boy> boy = Optional.of(new Boy());
          if (boy.isPresent()) {
              Boy boy1 = boy.get();
          }
          Optional<Object> empty = Optional.empty();
          Optional.ofNullable(null);
          Optional.ofNullable(new Girl());
      }
      
  • 判断Optional容器中是否包含对象:

    • boolean isPresent():判断是否包含对象
    • void ifPresent(Consumer<? super T> consumer):如果有值,就执行Consumer接口的实现代码,并且该值为作为参数传给它。
  • 获取Optional容器的对象:

    • T get():如果调用对象包含值,返回该值,否则抛异常

    • T orElse(T other):如果有值则将其返回,否则返回执行的other对象

    • T orElseGet(Supplier<? extends T> other):如果有值则将其返回,否则返回由Supplier接口实现提供的对象。

    • T orElseThrow(Supplier<? extends X> exceptionSupplier):如果有值则将其返回,否则抛出由Supplier接口实现提供的异常

    • public String getGirlName2(Boy boy){
          Optional<Boy> boy1 = Optional.ofNullable(boy);
          Boy boy2 = boy1.orElse(new Boy());
          Optional<Girl> girl = Optional.ofNullable(boy2.getGirl());
          Girl girl1 = girl.orElse(new Girl());
          return girl1.getName();
      }
      
      @Test
      public void test2(){
          System.out.println(getGirlName2(new Boy()));
      }
      

Optional类总结

  • optional类避免在程序中出现空指针异常
  • 常用方法:
    • ofNullable(T t)
    • orElse(T t)
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值