Java 8 新特性 (#Lambda表达式 #函数式(Functional)接口 #方法引用与构造器引用 #Stream API #Optional类)

  • 概述

Java 8 (又称为 jdk 1.8) 是 Java 语言开发的一个主要版本。 Java 8 是oracle公司于2014年3月发布,可以看成是自Java 5 以 来最具革命性的版本。Java 8为Java语言、编译器、类库、开发 工具与JVM带来了大量新特性。

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

  •  Lambda

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

语法格式

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

箭头操作符将Lambda分为两个部分:

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

六大格式

格式一:无参,无返回值

Runnable r2 = () -> {System.out.println("我也是中国人!");};

格式二:Lambda 需要一个参数,但是没有返回值。 

 Consumer<String> con2 = (String s) -> {System.out.println(s);};

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

 Consumer<String> con2 = (s) -> {System.out.println(s);};

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

 Consumer<String> con2 = s -> {System.out.println(s);};

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

Comparator<Integer> com2 = (o1,o2) -> {
    System.out.println("xxxxxxxxx");
    return Integer.compare(o1,o2);
};

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

Comparator<Integer> com2 = (o1,o2) -> Integer.compare(o1,o2);
  • 函数式(Functional)接口

理解函数式接口

  • Java从诞生日起就是一直倡导“一切皆对象”,在Java里面面向对象(OOP) 编程是一切。但是随着python、scala等语言的兴起和新技术的挑战,Java不 得不做出调整以便支持更加广泛的技术要求,也即java不但可以支持OOP还 可以支持OOF(面向函数编程)
  • 在函数式编程语言当中,函数被当做一等公民对待。在将函数作为一等公民的 编程语言中,Lambda表达式的类型是函数。但是在Java8中,有所不同。在 Java8中,Lambda表达式是对象,而不是函数,它们必须依附于一类特别的 对象类型——函数式接口。 
  • 简单的说,在Java8中,Lambda表达式就是一个函数式接口的实例。这就是 Lambda表达式和函数式接口的关系。也就是说,只要一个对象是函数式接口 的实例,那么该对象就可以用Lambda表达式来表示。
  • 所以以前用匿名实现类表示的现在都可以用Lambda表达式来写。

函数式接口的特点

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

自定义函数式接口

@FunctionalInterface
public interface A {
    String show(String s);
}

 函数式接口中使用泛型

@FunctionalInterface
public interface A<T> {
    public T show(T t);
}

用Lambda表达式实例化自定义函数接口

@Test
public void test11(){
    //***********常规写法***************"
    A a = new A<String>() {
        @Override
        public String show(String s) {
            return s;
        }
    }
    String zz = (String) a.show("zz");
    System.out.println(zz);
    //***********Lambda表达式写法***************"
    A a1 = s -> s;
    String yy = (String) a1.show("yy");
    System.out.println(yy);
}

作为参数传递 Lambda 表达式

@Test
public void test22(){
    List<String> list = Arrays.asList("北京","南京","天津","东京","西京");
    //"***********常规写法***************
    filterString(list, new Predicate<String>() {
        @Override
        public boolean test(String s) {
            return s.contains("京");
        }
    });
    //****************Lambda表达式写法***************
    List<String> list1 = filterString(list, s -> s.contains("京"));
    System.out.println(list1);
}

//根据给定的规则,过滤集合中的字符串。此规则由Predicate的方法决定
public List<String> filterString(List<String> list, Predicate<String> pre){
    List<String> filterList = new ArrayList<>();
    for (String s : list) {
        if (pre.test(s))
            filterList.add(s);
    }
    return filterList;
}

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

  • 方法引用、构造器引用、数组引用

方法引用

概述

  • 当要传递给Lambda体的操作,已经有实现的方法了,可以使用方法引用!
  • 方法引用,本质上就是Lambda表达式,而Lambda表达式作为函数式接口的实例。所以方法引用,也是函数式接口的实例。 
  • 使用格式:  类(或对象) :: 方法名
  • 方法引用使用的要求:要求接口中的抽象方法的形参列表和返回值类型与方法引用的方法的形参列表和返回值类型相同!(针对于下文的情况1和情况2)
  • 具体分为如下的三种情况:
  1.  对象 :: 非静态方法
  2.  类 :: 静态方法
  3.  类 :: 非静态方法

情况一:对象 :: 实例方法

@Test
public void test1(){
    Person p = new Person("张三",23);
    //***********常规写法***************"
    Supplier<String> sup = new Supplier<String>() {
        @Override
        public String get() {
            return p.getName();
        }
    };
    String s = sup.get();
    System.out.println(s);
    //***********Lambda表达式写法***************"
    Supplier<String> sup1 = () -> p.getName();
    System.out.println(sup1.get());
    //***********方法引用写法***************"
    Supplier<String> sup2 = p :: getName;
    System.out.println(sup2.get());

}

 情况二:类 :: 静态方法

@Test
public void test2(){
    //***********常规写法***************"
    Comparator<Integer> com1 = new Comparator<Integer>() {
        @Override
        public int compare(Integer o1, Integer o2) {
            return Integer.compare(o1,o2);//Integer类的静态方法compare()
        }
    };
    System.out.println(com1.compare(11, 22));//-1
    //***********Lambda表达式写法***************"
    Comparator<Integer> com2 = (o1, o2) -> Integer.compare(o1,o2);
    System.out.println(com2.compare(22,11));//1
    //***********方法引用写法***************"
    Comparator<Integer> com3 = Integer::compare;
    System.out.println(com3.compare(22, 33));//-1
}

情况三:类 :: 非静态方法

@Test
public void test3(){
    //***********常规写法***************"
    Comparator<String> com1 = new Comparator<String>() {
        @Override
        public int compare(String o1, String o2) {
            return o1.compareTo(o2);
        }
    };
    System.out.println(com1.compare("AA", "AB"));//-1
    //***********Lambda表达式写法***************"
    Comparator<String> com2 = (o1, o2) -> o1.compareTo(o2);
    System.out.println(com2.compare("AB", "AA"));
    //***********方法引用写法***************"
    Comparator<String> com3 = String :: compareTo;
    System.out.println(com3.compare("AB", "AC"));//-1
}

构造器引用

 概述

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

代码演示

空参构造器引用

@Test
public void test1(){
    //***********常规写法***************"
    Supplier<Person> sup1 = new Supplier<Person>() {
        @Override
        public Person get() {
            return new Person();
        }
    };
    Person person = sup1.get();
    System.out.println(person);
    //***********Lambda表达式写法***************"
    Supplier<Person> sup2 = () -> new Person();
    System.out.println(sup2.get());
    //***********构造器引用写法***************"
    Supplier<Person> sup3 = Person :: new;
    System.out.println(sup3.get());

}

带参构造器方法引用

@Test
public void test2(){
    //***********常规写法***************"
    BiFunction<String,Integer,Person> bf1 = new BiFunction<String, Integer, Person>() {
        @Override
        public Person apply(String s, Integer integer) {
            return new Person(s,integer);
        }
    };
    Person p1 = bf1.apply("Jack", 23);
    System.out.println(p1);
    //***********Lambda表达式写法***************"
    BiFunction<String,Integer,Person> bf2 = (s,integer) -> new Person(s,integer);
    System.out.println(bf2.apply("Tom", 24));
    //***********构造器引用写法***************"
    BiFunction<String,Integer,Person> bf3 = Person :: new;
    System.out.println(bf3.apply("Jerry", 25));
}

数组引用

概述

可以把数组看做是一个特殊的类,则写法与构造器引用一致。

代码演示

@Test
public void test3(){
    //***********常规写法***************"
    Function<Integer,String[]> fun1 = new Function<Integer, String[]>() {
        @Override
        public String[] apply(Integer integer) {
            return new String[integer];
        }
    };
    String[] arr1 = fun1.apply(5);
    System.out.println(Arrays.toString(arr1));
    //***********Lambda表达式写法***************"
    Function<Integer,String[]> fun2 = length -> new String[length];
    System.out.println(Arrays.toString(fun2.apply(6)));
    //***********数组引用写法***************"
    Function<Integer,String[]> fun3 = String[] ::new;
    System.out.println(Arrays.toString(fun3.apply(7)));
}
  • 强大的Stream API

概述

说明

  • Stream 是 Java8 中处理集合的关键抽象概念,它可以指定你希望对集合进行的操作,可以执行非常复杂的查找、过滤和映射数据等操作。 使用 Stream API 对集合数据进行操作,就类似于使用 SQL执行的数据库查询。 也可以使用 Stream API 来并行执行操作。简言之,Stream API 提供了一种 高效且易于使用的处理数据的方式。 
  • 实际开发中,项目中多数数据源都来自于Mysql,Oracle等。但现在数 据源可以更多了,有MongDB,Radis等,而这些NoSQL的数据就需要 Java层面去处理。

Stream 和 Collection 集合的区别 

Stream关注的是对数据的运算,与CPU打交道。集合关注的是数据的存储,与内存打交道 (“集合讲的是数据,Stream讲的是计算!)

Stream的特点

  • Stream是数据渠道,用于操作数据源(集合、数组等)所生成的元素序列。 
  • Stream 自己不会存储元素。
  • Stream 不会改变源对象。相反,他们会返回一个持有结果的新Stream。
  • Stream 操作是延迟执行的。这意味着他们会等到需要结果的时候才执行 

Stream执行流程

  1. Stream的实例化
  2.  一系列的中间操作(过滤、映射、...)
  3.  终止操作 

注意 :

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

Stream的实例化(创建Stream)

方式一:通过集合 

@Test
public void test1(){
    List<Person> peoples = new ArrayList<>();
    peoples.add(new Person("张三",23));
    peoples.add(new Person("李四",24));
    peoples.add(new Person("王五",25));
    peoples.add(new Person("赵六",26));

    //default Stream<E> stream() : 返回一个顺序流
    Stream<Person> stream = peoples.stream();
    //default Stream<E> parallelStream() : 返回一个并行流
    Stream<Person> stream1 = peoples.parallelStream();

}

 方式二:通过数组

public void test2(){
    Person p1 = new Person("张三",23);
    Person p2 = new Person("李四",24);

    //调用Arrays类的static <T> Stream<T> stream(T[] array): 返回一个流
    Person[] peoples = new Person[]{p1,p2};
    Stream<Person> stream = Arrays.stream(peoples);
}

 方式三:通过Stream的of()

@Test
public void test3(){
    Stream<String> stream = Stream.of("张三", "李四", "王五", "赵六");
}

 方式四:创建无限流

@Test
public void test4(){
    //迭代
    //public static<T> Stream<T> iterate(final T seed, final UnaryOperator<T> f)
    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的中间操作

说明

多个中间操作可以连接起来形成一个流水线,除非流水线上触发终止 操作,否则中间操作不会执行任何的处理!而在终止操作时一次性全 部处理,称为“惰性求值”。 

筛选与切片

  •  filter(Predicate p) 接收 Lambda , 从流中排除某些元素
    List<Worker> workersList = WorkerData.getWorkers();
    Stream<Worker> stream = workersList.stream();
    //filter(Predicate p)——接收 Lambda , 从流中排除某些元素。
    stream.filter(w -> w.getSalary() > 5000).forEach(System.out::println);//查询员工表中薪资大于5000的员工信息
  • distinct() 筛选,通过流所生成元素的 hashCode() 和 equals() 去除重复元素
    List<Worker> workersList = WorkerData.getWorkers();
    //distinct()——筛选,通过流所生成元素的 hashCode() 和 equals() 去除重复元素
    workersList.add(new Worker(1004, "雷军", 26, 7657.37));//原集合存在该条数据去重
    workersList.add(new Worker(1004, "雷军", 26, 8888));//和原数据salary不同,不会去除该条数据
    workersList.stream().distinct().forEach(System.out::println);
  • limit(long maxSize) 截断流,使其元素不超过给定数量
    List<Worker> workersList = WorkerData.getWorkers();
    // limit(n)——截断流,使其元素不超过给定数量。
    workersList.stream().limit(3).forEach(System.out::println);//获取集合中前三条数据
  • skip(long n) 跳过元素,返回一个扔掉了前 n 个元素的流。若流中元素不足 n 个,则返回一 个空流。与 limit(n) 互补
    List<Worker> workersList = WorkerData.getWorkers();
    //skip(n) —— 跳过元素,返回一个扔掉了前 n 个元素的流。若流中元素不足 n 个,则返回一个空流。与 limit(n) 互补
    workersList.stream().skip(3).forEach(System.out::println);//获取集合中除了前三条的其余数据

    映射

  • map(Function f) 接收一个函数作为参数,该函数会被应用到每个元素上,并将其映射成一个新的元素。
    @Test
    public void test(){
        //通过集合实例化Stream
        Stream<Worker> workerStream = WorkerData.getWorkers().stream();
        //通过map()方法反射出集合中所有员工名字
        Stream<String> streamName = workerStream.map(Worker::getName);
        //筛选出员工姓名长度大于3的员工的姓名。
       streamName.filter(name -> name.length() > 3).forEach(System.out::println);
    }
  • mapToDouble(ToDoubleFunction f) 接收一个函数作为参数,该函数会被应用到每个元素上,产生一个新的 DoubleStream。
  • mapToInt(ToIntFunction f) 接收一个函数作为参数,该函数会被应用到每个元素上,产生一个新的 IntStream。
  • mapToLong(ToLongFunction f) 接收一个函数作为参数,该函数会被应用到每个元素上,产生一个新的 LongStream。
  • flatMap(Function f) 接收一个函数作为参数,将流中的每个值都换成另一个流,然后把所有流连接成一个流 
    @Test
    public void test9(){
        List<String> list = Arrays.asList("aa", "bb", "cc", "dd");
        //Stream里还有Stream时,通过使用map()方法需要使用二次forEach()方法进行终止操作
        //可以通过集合添加元素的add()方法和addAll()方法进行理解
        Stream<Stream<Character>> streamStream = list.stream().map(StreamAPITest1::fromStringToStream);
        streamStream.forEach(s -> s.forEach(System.out::println));
        System.out.println("****************");
        //这里我们可以使用flatMap(Function f)方法进行处理者这种情况(相当于集合添加元素的addAll()方法)
        Stream<Character> streamStream1 = list.stream().flatMap(StreamAPITest1::fromStringToStream);
        streamStream1.forEach(System.out::println);
    }
    
    //将字符串中的多个字符构成的集合转换为对应的Stream的实例
    public static Stream<Character> fromStringToStream(String s){
        ArrayList<Character> list = new ArrayList<>();
        for (Character c : s.toCharArray()) {
            list.add(c);
        }
        return list.stream();
    }

排序

  • sorted() 产生一个新流,其中按自然顺序排序
    @Test
    public void test5(){
        List<Integer> list = Arrays.asList(11,22,44,77,33,55);
        list.stream().sorted().forEach(System.out::println);
    }

注意:自定义类要实现Comparable接口,才能使用sorted()方法

  • sorted(Comparator com) 产生一个新流,其中按比较器顺序排序 (定制排序)
    @Test
    public void test6(){
        List<Worker> workerList = WorkerData.getWorkers();
        workerList.stream().sorted((o1,o2) ->{
            int compareAge = Integer.compare(o1.getAge(),o2.getAge());
            if (compareAge != 0)
                return compareAge;
            else {
                int compareSalary = -Double.compare(o1.getSalary(), o2.getSalary());
                return compareSalary;
            }
        }).forEach(System.out::println);
    }

    Stream的终止操作(终端操作)

 匹配与查找

以下代码演示需要用到的Worker类的对象集合:

List<Worker> workerList = WorkerData.getWorkers();
  • allMatch(Predicate p) 检查是否匹配所有元素
    //需求:是否所有的员工的年龄都大于18
    boolean b = workerList.stream().allMatch(w -> w.getAge() > 20);
    System.out.println(b);
  • anyMatch(Predicate p) 检查是否至少匹配一个元素
    //需求:是否存在员工的工资大于 10000
    boolean b1 = workerList.stream().anyMatch(w -> w.getSalary() > 10000);
    System.out.println(b1);
  • noneMatch(Predicate p) 检查是否没有匹配所有元素
    //需求:是否存在员工姓“雷”
    boolean b2 = workerList.stream().noneMatch(w -> w.getName() == "张");
    System.out.println(b2);
  • findFirst() 返回第一个元素
    Optional<Worker> first = workerList.stream().findFirst();
    System.out.println(first);
  • findAny() 返回当前流中的任意元素 
    Optional<Worker> any = workerList.parallelStream().findAny();
    System.out.println(any);
  • count() 返回流中元素总数
    //需求:计算员工工资大于5000的员工个数
    long count = workerList.stream().filter(w -> w.getSalary() > 5000).count();
    System.out.println(count);
  • max(Comparator c) 返回流中最大值
    //需求:查找最高的员工工资
    Optional<Double> maxSalary = workerList.stream().map(w -> w.getSalary()).max(Double::compare);
    System.out.println(maxSalary);
  • min(Comparator c) 返回流中最小值
    //需求:查找最低的员工工资
        //写法一:
        Optional<Double> min = workerList.stream().map(w -> w.getSalary()).min((o1,o2) -> Double.compare(o1,o2));
        System.out.println(min);//Optional[2500.32]
        //写法一:
        Optional<Worker> minSalary = workerList.stream().min((w1, w2) -> Double.compare(w1.getSalary(), w2.getSalary()));
        System.out.println(minSalary);//Optional[Worker{id=1008, name='扎克伯格', age=35, salary=2500.32}]
  • forEach(Consumer c) 内部迭代(使用 Collection 接口需要用户去做迭代, 称为外部迭代。相反,Stream API 使用内部迭代——它帮你把迭代做了) 
    //使用集合的遍历操作
    workerList.forEach(System.out::println);
    System.out.println();
    //内部迭代
    workerList.stream().forEach(System.out::println);
    

规约

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

  • 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 sum = list.stream().reduce(0, (o1, o2) -> Integer.sum(o1, o2));
    //Integer sum = list.stream().reduce(0, Integer::sum);
    System.out.println(sum);//55
  • reduce(BinaryOperator b) 可以将流中元素反复结合起来,得到一 个值。返回 Optional  
    List<Worker> workerList = WorkerData.getWorkers();
    Optional<Double> sumSalary = workerList.stream().map(w -> w.getSalary()).reduce((s1, s2) -> s1 + s2);
    System.out.println(sumSalary);//Optional[48424.08]

收集

  •  collect(Collector c) 将流转换为其他形式。接收一个Collector接口的实现,用于给Stream中元素做汇总的方法
    @Test
    public void test3(){
        List<Worker> workerList = WorkerData.getWorkers();
        //把流中元素收集到List集合中
        List<Worker> collectList = workerList.stream().filter(w -> w.getSalary() > 5000).collect(Collectors.toList());
        collectList.forEach(System.out::println);
        System.out.println();
    
        //把流中元素收集到set集合中
        Set<Worker> collectList1 = workerList.stream().filter(w -> w.getSalary() > 5000).collect(Collectors.toSet());
        collectList1.forEach(System.out::println);
    }

    Collector 接口中方法的实现决定了如何对流执行收集的操作(如收集到 List、Set、 Map)。 另外,Collectors 实用类提供了很多静态方法,可以方便地创建常见收集器实例, 具体方法与实例如下表:

  • Optional类

概述

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

创建Optional类对象的方法

下方代码演示用到的Student类和Teacher类  

public class Student {
    private String name;

    public Student() {
    }

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

    public String getName() {
        return name;
    }

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

    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                '}';
    }
}
public class Teacher {
    private Student student;

    public Teacher() {
    }

    public Teacher(Student student) {
        this.student = student;
    }

    public Student getStudent() {
        return student;
    }

    public void setStudent(Student student) {
        this.student = student;
    }

    @Override
    public String toString() {
        return "Teacher{" +
                "student=" + student +
                '}';
    }
}
  • Optional.of(T t) : 创建一个 Optional 实例,t必须非空
@Test
public void test1(){
    Student student = new Student();
    //student = null;//java.lang.NullPointerException
    Optional<Student> optionalStudent = Optional.of(student);
}
  • Optional.ofNullable(T t):t可以为null 
@Test
public void test2(){
    Student student = new Student();
    student = null;
    //ofNullable(T t):t可以为null
    Optional<Student> optionalStudent = Optional.ofNullable(student);
}
  • Optional.empty() : 创建一个空的 Optional 实例
Optional<Object> empty = Optional.empty();

 判断Optional容器中是否包含对象

  • boolean isPresent() : 判断是否包含对象
    @Test
    public void test4() {
        Student student = new Student();
        //student = null;
        Optional<Student> optionalStudent = Optional.ofNullable(student);
        boolean present = optionalStudent.isPresent();
        System.out.println(present);//true(如果对象为null 返回为false)
    }
  • void ifPresent(Consumer consumer) :如果有值,就执行Consumer 接口的实现代码,并且该值会作为参数传给它。
    @Test
    public void test5(){
        Student stu = new Student();
        stu.setName("张三");
        //stu = null;//如果对象为null时,ifPresent()方法返回为空
        Optional<Student> optionalStudent = Optional.ofNullable(stu);
        //方式1:
        optionalStudent.ifPresent(student -> System.out.println(student.getName()));
        //方式二:
        optionalStudent.ifPresent(new Consumer<Student>() {
            @Override
            public void accept(Student student) {
                System.out.println(student.getName());
            }
        });
    }

    获取Optional容器的对象 

  • T get(): 如果调用对象包含值,返回该值,否则抛异常
    @Test
    public void test6(){
        Student student = new Student();
        Optional<Student> optionalStudent = Optional.of(student);
        Student stu = optionalStudent.get();
        System.out.println(stu);
    }
  • T orElse(T other) :如果有值则将其返回,否则返回指定的other对象。
    public String getStudentName(Teacher teacher){
        //return teacher.getStudent().getName();//这样写会出现空指针异常
    
        //Java1.8之前没引进Optional类的写法
        /*if (teacher != null) {
            Student student = teacher.getStudent();
            if (student != null){
                return student.getName();
            }
        }
        return null;*/
    
        //Java1.8引进Optional类的写法
        Optional<Teacher> teacher1 = Optional.ofNullable(teacher);
        //此时的teacher2一定非空(如果teacher1为空,则返回Jerry,如果不为空,则返回实际的对象)
        Teacher teacher2 = teacher1.orElse(new Teacher(new Student("Jerry")));
        Student student = teacher2.getStudent();
        Optional<Student> student1 = Optional.ofNullable(student);
        //此时的student2一定非空(如果student1为空,则返回Tom,如果不为空,则返回实际的对象)
        Student student2 = student1.orElse(new Student("Tom"));
        return student2.getName();
    }
  • T orElseGet(Supplier other) :如果有值则将其返回,否则返回由Supplier接口实现提供的对象。
    @Test
    public void test8(){
        Teacher teacher = new Teacher(new Student("Jane"));
        Optional<Teacher> teacher1 = Optional.ofNullable(teacher);
        Teacher teacher2 = teacher1.orElseGet(() -> new Teacher(new Student("Jerry")));
        Student student = teacher2.getStudent();
        Optional<Student> student1 = Optional.ofNullable(student);
        Student student2 = student1.orElseGet(new Supplier<Student>() {
            @Override
            public Student get() {
                return new Student("Tom");
            }
        });
        System.out.println(teacher2);//Teacher{student=Student{name='Jane'}}
        System.out.println(student2);//Student{name='Jane'}
  • T orElseThrow(Supplier exceptionSupplier) :如果有值则将其返回,否则抛出由Supplier接口实现提供的异常。
    @Test
    public void test9() throws Throwable {
        Teacher teacher = new Teacher();
        teacher = null;
        Optional<Teacher> teacher1 = Optional.ofNullable(teacher);
        Teacher teacher2 = teacher1.orElseThrow(new Supplier<Throwable>() {
            @Override
            public Throwable get() {
                return new MyException("异常", 001);
            }
        });
        System.out.println(teacher2);
    }
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值