对于Java8的新特性,应该了解(掌握)的哪些

Java8的新特性


速度更快,代码更少(Lambda表达式),强大的Stream API,便于并行,最大化
减少空指针异常(Optional),Nashorn引擎,允许在JVM上允许jS应用

一、Lambda表达式

1.Lambda是一个匿名函数,我们可以把Lambda表达式理解为是一段可以传递的代码,使用它可以写出更简洁、更灵活的代码.

  1. Lambda表达式:在java8语言中引入的一种新的语法元素和操作符,这个操作符为"->" ,该操作符为称为Lambda操作符
    或者箭头操作符,他将Lambda分成两部分:

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

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

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

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

基本的使用方式
    @Test
    public void test1(){
        Comparator<Integer> comparator =new Comparator<Integer>() {
            @Override
            public int compare(Integer o1, Integer o2) {
                return Integer.compare(o1,o2);
            }
        };
        int compare = comparator.compare(12, 21);
        System.out.println(compare);

        System.out.println("***********************");
        //Lambda表达式
        Comparator<Integer> comparator1 = (o1,o2) ->Integer.compare(o1,o2);
        int compare1 = comparator1.compare(32, 23);
        System.out.println(compare1);

        System.out.println("********************");

        //方法引用
        Comparator<Integer> comparator2 = Integer::compare;

        int compare2 = comparator2.compare(23, 21);
        System.out.println(compare2);
    }
Lambda表达式的使用:6种情况

总结:
左边:lambda形参列表的参数类型可以省略(类型推断),如果lambda形参列表只有一个参数,可以省略括号。

右边:lambda体应该使用一对{}包裹,如果lambda体只有一条执行语句(或return时),可以省略括号不写。

语法格式一:无参,无返回值
@Test
    public void test(){
        Runnable runnable = new Runnable() {
            @Override
            public void run() {
                System.out.println("Lambda表达式");
            }
        };
        //对象调方法
        runnable.run();

        System.out.println("*************************");

        //箭头操作符
        Runnable runnable1 =() -> System.out.println("Lambda表达式111");

        //对象调方法
        runnable1.run();
    }
语法格式二:Lambda表达式需要一个参数,但是没有返回值
 @Test
    public void test1(){
        Consumer<String> consumer =new Consumer<String>() {
            @Override
            public void accept(String s) {
                System.out.println(s);
            }
        };
        consumer.accept("语法格式二:Lambda表达式需要一个参数,但是没有返回值1");

        System.out.println("*********************");
        //Lambda表达式的写法
        Consumer<String> consumer1 = (String s) -> {  System.out.println(s);};
        consumer1.accept("语法格式二:Lambda表达式需要一个参数,但是没有返回值2");

    }
语法格式三:数据类型可以省略,因为可由编译器推断得出,称为"类型推断"
    @Test
    public void test2(){
        Consumer<String> consumer = (String s) -> {
            System.out.println(s);
        };
        consumer.accept("语法格式三:数据类型可以省略,因为可由编译器推断得出,称为类型推断");

        System.out.println("********************");
        Consumer<String> consumer1 = ( s) -> {//类型推断
            System.out.println(s);
        };
        consumer1.accept("语法格式三:数据类型可以省略,因为可由编译器推断得出,称为类型推断1");
    }
语法格式四:Lambda 若只需要一个参数,参数的小括号也可以省略
   @Test
    public void test3(){
        Consumer<String> consumer1 = ( s) -> {//类型推断
            System.out.println(s);
        };
        consumer1.accept("语法格式四:Lambda 若只需要一个参数,参数的小括号也可以省略");

        System.out.println("***********************");

        Consumer<String> consumer = s -> {//类型推断
            System.out.println(s);
        };
        consumer.accept("语法格式四:Lambda 若只需要一个参数,参数的小括号也可以省略1");
    }
语法格式五:lambda表达式需要两个或以上参数,多条执行语句,并且可以有返回值
   @Test
    public void test4(){

       Comparator<Integer> comparator =  new Comparator<Integer>(){

           @Override
           public int compare(Integer o1, Integer o2) {
               System.out.println(o1);
               System.out.println(o2);
               return o1.compareTo(o2);
           }
       };
        System.out.println(comparator.compare(12,21));

        System.out.println("****************");

        Comparator<Integer> comparator1 = (o1,o2) -> {
            System.out.println(o1);
            System.out.println(o2);
            return o1.compareTo(o2);
        };
        System.out.println(comparator1.compare(23,13));
    }
语法格式六:当lambda体只有一条语句时,return 与 大括号若有,都可以省略
 @Test
    public void test5(){
        Comparator<Integer> comparator1 = (o1,o2) -> {
            System.out.println(o1);
            System.out.println(o2);
            return o1.compareTo(o2);
        };
        System.out.println(comparator1.compare(23,13));

        System.out.println("****************");

        Comparator<Integer> comparator2 = (o1,o2) -> o1.compareTo(o2);

        System.out.println(comparator2.compare(23,13));
    }
二、 java8 四大内置核心函数式接口

2.1、Consumer:消费型接口 —> void accept(T t)

2.2、Supplier:供给型接口 —> T get()

2.3、Function<T, R>:函数型接口 —> R apply(T t)

2.4、Predicate:断言型接口 —> boolean test(T t)

其他的函数式接口
1.BiFunction<T, U, R>
参数类型有2个,为T,U,返回值为R,对类型T,U参数的应用操作,其中方法为R apply(T t, U u)

2.UnaryOperator(Function子接口)
参数为T,对参数为T的对象进行一元操作,并返回T类型结果,其中方法为T apply(T t)

3.BinaryOperator(BiFunction子接口)
参数为T,对参数为T得对象进行二元操作,并返回T类型得结果,其中方法为T apply(T t1, T t2)

4.BiConsumcr(T, U)
参数为T,U无返回值,其中方法为 void accept(T t, U u)

5.ToIntFunction、ToLongFunction、ToDoubleFunction
参数类型为T,返回值分别为int,long,double,分别计算int,long,double得函数。

6.IntFunction、LongFunction、DoubleFunction
参数分别为int,long,double,返回值为R。

2.1、Consumer:消费型接口 —> void accept(T t)
    @Test
    public void test(){
        happTime(500, new Consumer<Double>() {
            @Override
            public void accept(Double aDouble) {
                System.out.println("Consumer<T>:消费型接口 ---> void accept(T t): " + aDouble);
            }
        });
        System.out.println("*******************");
        //lambda表达式
        happTime(450,money -> System.out.println("Consumer<T>:消费型接口 ---> void accept(T t): " + money));

    }

    public void happTime(double money, Consumer<Double> con){
        con.accept(money);
    }
2.4、Predicate:断言型接口 —> boolean test(T t)
 @Test
    public void test1(){
        List<String> list = Arrays.asList("刘备","刘邦","刘婵","流畅","流弊","刘二狗");
        List<String> strings = filterString(list, new Predicate<String>() {
            @Override
            public boolean test(String s) {
                return s.contains("刘");
            }
        });
        System.out.println(strings);//[刘备, 刘邦, 刘婵, 刘二狗]

        System.out.println("*********************");
        //lambda表达式
        List<String> strings1 = filterString(list,s -> s.contains("刘"));
        System.out.println(strings1);
     }

    //根据特点的规则,过滤集合中的字符串,此规则由Predicate的方法决定
    public List<String> filterString(List<String> list, Predicate<String> pre){

        ArrayList<String> filterList = new ArrayList<>();

        for (String s : list){
            if (pre.test(s)){
                filterList.add(s);
            }
        }
        return filterList;
    }
三、方法引用和构造器引用

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

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

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

4.格式:使用操作符"::"将类(或对象)与方法名分隔开来

如下三种主要使用情况:
①对象::实例方法名
②类::静态方法名
③类::实例方法名

方法引用的实例
 @Test
    public void test(){
        Comparator<Integer> com1 = (t1,t2) ->Integer.compare(t1,t2);
        System.out.println(com1.compare(12,21));

        System.out.println("**********************");

        Comparator<Integer> com2 = Integer::compare;
        System.out.println(com2.compare(12,3));

    }

    @Test
    public void test1(){
        Function<Double,Long> function = new Function<Double, Long>() {
            @Override
            public Long apply(Double aDouble) {
                return Math.round(aDouble);
            }
        };
        System.out.println("************************");

        Function<Double,Long> function1 =d -> Math.round(d);
        System.out.println(function1.apply(12.3));

        System.out.println("**************************");

        Function<Double,Long> function2 =  Math::round;
        System.out.println(function1.apply(12.6));
    }

    //情况三
    @Test
    public void test2(){
        Comparator<String> com1 =(s1,s2) -> s1.compareTo(s2);
        System.out.println(com1.compare("abc", "abd"));

        System.out.println("*************************");
        //方法引用
        Comparator<String> com2 = String::compareTo;
        System.out.println(com2.compare("abd", "abm"));//-9

    }
    @Test
    public void test3(){
        //比较两个参数,是否相等
        BiPredicate<String,String> pre1 = (s1,s2) ->s1.equals(s2);
        System.out.println(pre1.test("abc","abc"));//true

        System.out.println("**********************");

        BiPredicate<String,String> pre2 = String::equals;
        System.out.println(pre2.test("abc","abd"));//false
    }
    @Test
    public void test4(){
        Consumer<String> consumer1 = str -> System.out.println(str);
        consumer1.accept("北京");

        System.out.println("***********************");

        PrintStream ps = System.out;
        Consumer<String > consumer2 =ps::println;
        consumer2.accept("beijing");

    }
构造器引用和数组引用

构造器引用

1.Supplier中的T get()
2.Function中的R apply(T t)

  @Test
    public void test(){
        Supplier<Employee> sup = new Supplier<Employee>() {
            @Override
            public Employee get() {
                return new Employee();
            }
        };
        System.out.println(sup.get());
        System.out.println("*********************");

        Supplier<Employee> sup1 = () -> new Employee();

        System.out.println("************************");

        Supplier<Employee> sup2 = Employee::new;

    }
数组引用

Function中的R apply(T t)

    @Test
    public void test1(){
        Function<Integer,String[]> function1 = length -> new String[length];
        String[] arr = function1.apply(5);
        System.out.println(Arrays.toString(arr));//[null, null, null, null, null]

        System.out.println("******************");

        Function<Integer,String[]> function2 = String[]::new;
        String[] arr1 = function2.apply(10);
        System.out.println(Arrays.toString(arr1));
    }
三、函数式接口:只有一个抽象方法的接口,我们可以在接口中使用@FunctionalInterface来检查他是否是函数式接口

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

@FunctionalInterface
public interface MyInterface {//只能有应该抽象方法
    void method();
}
四、强大的Stream API

Stream API:把真正的函数式编程风格引入到了Java中,这是目前为止对java类库的最后的补充, 因为Stream API 可以极大的提供生产力,让代码更加的简洁、干净、高效率

1.使用Stream API 对集合数据进行操作,就类似于SQL执行的数据库查询,
Stream 和Collection集合的区别:Collection是一种静态的内存数据结构,而Stream是有关计算的。前者是主要面向内存的,存储在内存的,后者主要是面向CPU, 通过CPU实现计算。

2.什么是Stream?
是数据渠道,用于操作数据源(集合,数组等)所生成的元素序列。“集合讲的是数据,Stream讲的是计算!”

3.注意:

①Stream自己不会存储对象。

②Stream不会改变源对象,相反,他们会返回一个持有结果的新Stream。

③Stream操作是延迟执行的,这意味着他们会等到需要结果的时候才执行。

4.Stream的操作的三个步骤

①创建Stream:一个数据源(集合,数组),获取一个流()实例化

②中间操作:一个中间的操作(过滤,排序、映射、归约…)链,对数据源的数据进行处理

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

Stream API的测试类1
public class Employee {
    private int id;
    private String name;
    private int age;
    private double salary;


    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public double getSalary() {
        return salary;
    }

    public void setSalary(double salary) {
        this.salary = salary;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;

        Employee employee = (Employee) o;

        if (id != employee.id) return false;
        if (age != employee.age) return false;
        if (Double.compare(employee.salary, salary) != 0) return false;
        return name != null ? name.equals(employee.name) : employee.name == null;
    }

    public Employee() {
    }

    @Override
    public int hashCode() {
        int result;
        long temp;
        result = id;
        result = 31 * result + (name != null ? name.hashCode() : 0);
        result = 31 * result + age;
        temp = Double.doubleToLongBits(salary);
        result = 31 * result + (int) (temp ^ (temp >>> 32));
        return result;
    }

    @Override
    public String toString() {
        return "Employee{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", age=" + age +
                ", salary=" + salary +
                '}';
    }

    public Employee(int id, String name, int age, double salary) {
        this.id = id;
        this.name = name;
        this.age = age;
        this.salary = salary;
    }

    public Employee(int id, String name, int age) {
        this.id = id;
        this.name = name;
        this.age = age;
    }

    public Employee(int id, String name) {
        this.id = id;
        this.name = name;
    }

    public Employee(int id) {
        this.id = id;
    }
}

Stream API的测试类2
public class EmployeeData {
    public static List<Employee> getEmployees(){
        List<Employee> list = new ArrayList<>();

        list.add(new Employee(1001,"张三1",18,1234));
        list.add(new Employee(1002,"张三2",19,3244));
        list.add(new Employee(1003,"张三3",20,14545));
        list.add(new Employee(1004,"张三4",21,215));
        list.add(new Employee(1005,"张三5",22,2154));
        list.add(new Employee(1006,"张三6",23,5788));
        list.add(new Employee(1007,"张三7",24,2894));
        list.add(new Employee(1008,"张三8",25,9845));
        list.add(new Employee(1009,"张三9",26,25854));
        return list;
    }
}

测试Stream的实例化
创建Stream方式一:通过集合
   @Test
    public void test(){
        List<Employee> employees = EmployeeData.getEmployees();
        //default Stream<E> stream():返回一个顺序流
        Stream<Employee> stream = employees.stream();

        //default Stream<E> parallelStream():返回一个并行流
        Stream<Employee> stream1 = employees.parallelStream();

    }
创建Stream方式二:通过数组
   @Test
    public void test1(){
        int[] arr = new int[]{1,2,3,4,5};
        //调用Arrays类的static <T> Stream<T> stream(T[] array):返回一个流
        IntStream stream = Arrays.stream(arr);


        Employee employee1 =new Employee(1001,"Tom");
        Employee employee2 =new Employee(1002,"Jerry");
        Employee[] employees = new Employee[]{employee1,employee2};
        Stream<Employee> stream1 = Arrays.stream(employees);

    }
创建Stream方式三:通过Stream的of()
 @Test
    public void test2(){
        Stream<Integer> stream = Stream.of(1, 2, 3, 4, 5, 6);
        
    }
创建Stream方式四:创建无限流
    @Test
    public void test3(){
        //迭代
        //public static<T> Stream<T> iterate(final T seed,final UnaryOperator<T> f)
        //遍历前10个偶数
        Stream.iterate(0,t-> t + 2).limit(10).forEach(System.out::println);


        //生成
        //public static<T> Stream<T> generate(Supplier<T> s)
        Stream.generate(Math::random).limit(10).forEach(System.out::println);

    }
Stream的中间操作:多个中间操作可以连接成一个流水线,除非流水线上的触发终止操作,否则中间操作不会执行任何的处理,而是在终止操作时一次性全部处理称为"惰性求值"

一.筛选与切片

1、filter(Predicate p)——过滤Lambda , 从流中排除某些元素。

2、limit(n)——截断,使其元素不超过给定数量。

3、skip(n) —— 跳过元素,返回一个扔掉了前 n 个元素的流。若流中元素不足 n 个,则返回一个空流。与 limit(n) 互补

4、distinct——除重,通过流所生成元素的 hashCode() 和 equals() 去除重复元素

  @Test
   public void test(){
       List<Employee> list = EmployeeData.getEmployees();
       // 1、filter(Predicate p)——过滤Lambda , 从流中排除某些元素。
       Stream<Employee> stream = list.stream();
       //查询大于3000的salary数
       stream.filter(e -> e.getSalary() > 3000).forEach(System.out::println);

       System.out.println("********************");

       //2、limit(n)——截断,使其元素不超过给定数量。
       //异常IllegalStateException,一旦进行终止操作,就关闭了,的重新创建
       //stream.limit(3).forEach(System.out::println);
       list.stream().limit(3).forEach(System.out::println);

       System.out.println("*********************");
       //3、skip(n) —— 跳过,返回一个扔掉了前 n 个元素的流。
       list.stream().skip(3).forEach(System.out::println);

       System.out.println("******************");
       //4、distinct——除重,通过流所生成元素的 hashCode() 和 equals() 去除重复元素
       list.add(new Employee(1010,"张三10",2285));
       list.add(new Employee(1010,"张三10",2285));
       list.add(new Employee(1010,"张三10",2285));
       list.add(new Employee(1010,"张三10",2285));

       list.stream().distinct().forEach(System.out::println);
   }

二、映射

@Test
   public void test1(){
       /*
       2.1、map(Function f):接收一个函数作为参数,将元素转换为其他形式或提取信息,该函数会被应用到
       每个元素上,并将其映射成为一个新的元素。
       2.2、flatMap(Function f):接收一个函数作为参数,
       将流中的每一个值都转换成为另一个流,然后把流连接成一个流
        */
       List<String> list = Arrays.asList("aa", "bb", "cc", "dd");
       list.stream().map( str -> str.toUpperCase()).forEach(System.out::println);

       //练习1:
       List<Employee> employees = EmployeeData.getEmployees();
       Stream<String> stringStream = employees.stream().map(Employee::getName);
       stringStream.filter(name -> name.length() > 3).forEach(System.out::println);

       System.out.println("***************");
       //练习2:得到list中的一个个的字符
       Stream<Stream<Character>> streamStream = list.stream().map(StreamAPITest1::formStringToStream);
       streamStream.forEach(s ->{
           s.forEach(System.out::print);//aabbccdd
       });

       /*
        2.2、flatMap(Function f):接收一个函数作为参数,
       将流中的每一个值都转换成为另一个流,然后把流连接成一个流
        */
       Stream<Character> characterStream = list.stream().flatMap(StreamAPITest1::formStringToStream);
       characterStream.forEach(System.out::print);//aabbccdd

   }
   //将字符串中的多个字符构成的集合转换为对应的Stream的实例
   public static Stream<Character> formStringToStream(String str){
       ArrayList<Character> list = new ArrayList<>();
       for (Character character:str.toCharArray()){
           list.add(character);
       }
       return list.stream();
   }

三、排序

  @Test
    public void  test2(){
       //sorted()---自然排序
        List<Integer> list = Arrays.asList(12,254,45,0,-52,43,7);
        list.stream().sorted().forEach(System.out::println);

        System.out.println("*******************");

        //抛异常:原因:Employee没有实现Comparable接口
        //在java中涉及到对象的排序Comparator和Comparable
//        List<Employee> employees = EmployeeData.getEmployees();
//        employees.stream().sorted().forEach(System.out::println);

        //sorted(Comparator com) ---定制排序
        //方式一
//        List<Employee> employees = EmployeeData.getEmployees();
//        employees.stream().sorted((e1,e2) -> {
//            //按照年龄排序
//            return  Integer.compare(e1.getAge(),e2.getAge());
//
//        }).forEach(System.out::println);

        //方式二
        List<Employee> employees = EmployeeData.getEmployees();
        employees.stream().sorted((e1,e2) -> {
            //按照年龄排序,年龄相同salary按照排
            int ageValue = Integer.compare(e1.getAge(),e2.getAge());
            if (ageValue!=0){
                return ageValue;
            }else {
                return -Double.compare(e1.getSalary(),e2.getSalary());
            }


        }).forEach(System.out::println);

    }
Stream的终止操作

1.匹配与查找

allMatch(Predicate p) 检查是否匹配所有元素

anyMatch(Predicate p) 检查是否至少匹配一个元素

noneMatch(Predicate p) 检查是否没有匹配所有元素

findFirst() 返回第一个元素

findAny() 返回当前流中的任意元素

count() 返回流中总数

max(Comparator c) 返回流中最大值

min(Comparator c) 返回流中最小值

forEach(Consumer c) 内部迭代(使用 Collection 接口需要用户去做迭代,称为外部迭代。

 @Test
    public void test() {
        //allMatch(Predicate p)	检查是否匹配所有元素
        List<Employee> employees = EmployeeData.getEmployees();
        boolean anyMatch = employees.stream().anyMatch(e -> e.getAge() > 18);
        System.out.println(anyMatch);//true

//        anyMatch(Predicate p)	检查是否至少匹配一个元素
        boolean anyMatch1 = employees.stream().anyMatch(e -> e.getSalary() > 10000);
        System.out.println(anyMatch1);//true
//        noneMatch(Predicate p)	检查是否没有匹配所有元素
        boolean noneMatch = employees.stream().noneMatch(e -> e.getName().startsWith("张"));
        System.out.println(noneMatch);//false
//        findFirst()	返回第一个元素
        Optional<Employee> first = employees.stream().findFirst();
        System.out.println(first);//Optional[Employee{id=1001, name='张三1', age=18, salary=1234.0}]
//        findAny()	返回当前流中的任意元素
        Optional<Employee> any = employees.parallelStream().findAny();
        System.out.println(any);//Optional[Employee{id=1001, name='张三1', age=18, salary=1234.0}]
//        count()	返回流中总数
        long count = employees.stream().filter(e -> e.getSalary() > 3000).count();
        System.out.println(count);//5
//        max(Comparator c)	返回流中最大值
        Stream<Double> doubleStream = employees.stream().map(e -> e.getSalary());
        Optional<Double> maxSalary = doubleStream.max(Double::compare);
        System.out.println(maxSalary);//Optional[25854.0]
//        min(Comparator c)	返回流中最小值
        Optional<Employee> min = employees.stream().min((e1, e2) -> Double.compare(e1.getSalary(), e2.getSalary()));
        System.out.println(min);//Optional[Employee{id=1004, name='张三4', age=21, salary=215.0}]
//        forEach(Consumer c)	内部迭代(使用 Collection 接口需要用户去做迭代,称为外部迭代)。
        System.out.println("*****************");
        employees.stream().forEach(System.out::println);//终止操作
    }

2.归约
reduce(T identity, BinaryOperator b) 可以将流中元素反复结合起来,得到一个值。返回 T

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

    @Test
    public void test1(){
//        reduce(T iden, BinaryOperator b)
        List<Integer> list = Arrays.asList(1,2,3,4,5,6,7,8,9,10);
        Integer reduce = list.stream().reduce(0, Integer::sum);
        System.out.println(reduce);//55 累加和
//        reduce(BinaryOperator b)
        List<Employee> employees = EmployeeData.getEmployees();
        Stream<Double> stream = employees.stream().map(Employee::getSalary);
        Optional<Double> reduce1 = stream.reduce(Double::sum);
        System.out.println(reduce1);//Optional[65773.0]求总金额
    }

3.收集

    @Test
    public void test2(){
        //collect (Collector c)	将流转换为其他形式,接收一个Collector接口的实现,用于给Stream中元素做汇总的方法
        //Collector接口中方法的实现决定了如何对流执行收集操作(如收集到List,Set,Map).
        // 但是Collectors实现类中提供了许多静态方法,可以方便的创建常见的收集器实例.
        List<Employee> employees = EmployeeData.getEmployees();
        List<Employee> collect = employees.stream().filter(e -> e.getSalary() > 3000).collect(Collectors.toList());
        collect.forEach(System.out::println);//返回salary大于3000的集合

    }
五、 Optional类:为例避免空指针异常而创建的。

1.NullPointerException相信每个JAVA程序员都不陌生,是JAVA应用程序中最常见的异常。之前,Google Guava项目曾提出用Optional类来包装对象从而解决NullPointerException。受此影响,JDK8的类中也引入了Optional类

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

Optional.of(T t) : 创建一个 Optional 实例。

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

Optional.ofNullable(T t):若 t 不为 null,创建 Optional 实例,否则创建空实例。
isPresent() : 判断是否包含值。

orElse(T t) : 如果调用对象包含值,返回该值,否则返回t。

orElseGet(Supplier s) :如果调用对象包含值,返回该值,否则返回 s 获取的值。

map(Function f): 如果有值对其处理,并返回处理后的Optional,否则返回 Optional.empty()。

flatMap(Function mapper):与 map 类似,要求返回值必须是Optional。

Optional测试类1
public class Boy {
    private Girl girl;

    @Override
    public String toString() {
        return "Boy{" +
                "girl=" + girl +
                '}';
    }

    public Girl getGirl() {
        return girl;
    }

    public void setGirl(Girl girl) {
        this.girl = girl;
    }

    public Boy() {
    }

    public Boy(Girl girl) {
        this.girl = girl;
    }
}

Optional测试类2
public class Girl {

    private String name;

    @Override
    public String toString() {
        return "Girl{" +
                "name='" + name + '\'' +
                '}';
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Girl() {
    }

    public Girl(String name) {
        this.name = name;
    }
}

创建Optional类和对象的方法

 @Test
    public void test() {
//Optional.of(T t) : 创建一个 Optional 实例。
        Girl girl = new Girl();
        //如果为空,就出现空指针异常
        //girl = null;
        Optional<Girl> optionalGirl = Optional.of(girl);
//Optional.ofNullable(T t):若 t 不为 null,创建 Optional 实例,否则创建空实例。
    }
    @Test
    public void test1(){
        //Optional.ofNullable(T t):若 t 不为 null,创建 Optional 实例,否则创建空实例。
        Girl girl = new Girl();
        girl = null;
        Optional<Girl> optionalGirl = Optional.ofNullable(girl);
        System.out.println(optionalGirl);//Optional.empty

        //orElse(T t1):如果当前的Optional内部封装的t时非空的,就将其返回的t
        //如果内部的t时空的,就返回toElse()方法中的参数t1。
        Girl girl1 = optionalGirl.orElse(new Girl("张三"));
        System.out.println(girl1);//Girl{name='张三'}
    }

    public String getGirlName(Boy boy){
        return boy.getGirl().getName();
    }

    @Test
    public void tets2(){
        Boy boy = new Boy();
        String girlName = getGirlName(boy);
        System.out.println(girlName);//出现空指针异常
    }

    //优化后的getGirlName方法
    public String getGirlName1(Boy boy){
       if(boy != null){
           Girl girl = boy.getGirl();
           if (girl !=null){
               return girl.getName();
           }
       }
       return null;
    }
    @Test
    public void tets3(){
        Boy boy = new Boy();
        String girlName = getGirlName1(boy);
        System.out.println(girlName);//null
    }

    //使用Optional类的getGirlName()
    public String getGirlName2(Boy boy){
        Optional<Boy> optionalBoy = Optional.ofNullable(boy);

        Boy boy1 = optionalBoy.orElse(new Boy(new Girl("张三三")));

        Girl girl = boy1.getGirl();

        Optional<Girl> girlOptional = Optional.ofNullable(girl);

        //此时girl1中的数据一定为空
        Girl girl1 = girlOptional.orElse(new Girl("张四四"));


        return girl1.getName();
    }
    @Test
    public void test4(){
        Boy boy = null;//张三三
        boy = new Boy();//张四四
        String girlName2 = getGirlName2(boy);
        System.out.println(girlName2);
    }
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值