(二)Optional
概述
在编写代码的时候出现最多的就是空指针异常。所以在很多情况下我们需要做各种非空的判断。JDK8中引入了Optional,使用Optional可以更优雅的避免空指针异常;
1.三种创建Optional对象方式
Optional就好像是包装类,可以把我们的具体数据封装到Optional对象内部。然后我们去使用Optional中封装好的方法操作封装进去的数据就可以优雅的避免空指针异常;
1.1.Optional.ofNullable(T value)
Optional.ofNullable(T value)
此方式无论封装对象是否为null,在封装为Optional对象时都不会有空指针问题;
推荐方式
/*** Optional.ofNullable(T value)*/public static void test1(){Author author = null;// 使用Optional.ofNullable(T value)将任意类型转为Optional对象【*推荐*,此方式将任意对象转为Optional对象时无空指针问题】Optional<Author> optionalAuthor = Optional.ofNullable(author);// 消费Optional中的数据; ifPresent()不为null则消费Optional中的数据optionalAuthor.ifPresent(author1 -> System.out.println(author1.getName()));}
1.2.Optional.of(T value)
Optional.of(T value)
封装对象若为null,调用Optional.of(T value)方法会出现空指针(当封装对象必定不为null时可使用此方法将封装对象转换为Optional);
/*** Optional.of(T value)*/public static void test2(){Author author = null;// 封装对象若为null,调用Optional.of(T value)方法会出现空指针Optional<Author> optionalAuthor = Optional.of(author);}
1.3.Optional.empty()
Optional.empty()
返回一个空的Optional对象;
/*** Optional.empty()*/private static void test3() {// 返回一个空的Optional对象Optional<Object> optional = Optional.empty();}
2.安全的消费Optional中值
获取到一个Optional对象后肯定需要对其中的数据进行使用。这时候我们可以使用ifPresent方法来消费其中的值。这个方法会判断其内封装的数据是否为空,不为空时才会执行具体的消费代码;
ifPresent(Consumer<? super T> consumer)
内部封装数据不为null时才进行消费;
private static void test4() {Author authorOne = null;Author authorTwo = new Author();authorTwo.setName("张三");// authorOne对象为null故使用ifPresent方法时不会执行具体的消费代码Optional<Author> optionalAuthor = Optional.ofNullable(authorOne);optionalAuthor.ifPresent(author -> System.out.println(author.getName()));// authorTwo对象不为null故使用ifPresent方法时会执行具体的消费代码Optional<Author> optionalAuthor2 = Optional.ofNullable(authorTwo);optionalAuthor2.ifPresent(author -> System.out.println(author.getName()));}
3.安全的获取Optional中值
学习安全获取Optional中值时先了解一种不安全的获取值方式get()方法;
/*** 不安全的获取Optional中值* get()方法*/private static void test5() {Optional<String> optional = Optional.ofNullable(null);// 不安全的获取值,当Optional中值为null时调用get方法会抛出 NoSuchElementException异常String result = optional.get();}
3.1.orElseGet
orElseGet(Supplier<? extends T> other)
获取数据并设置数据为null时的默认值。如果数据不为null就获取该数据。为null则返回设置的默认值;
/*** 安全获取值* orElseGet*/private static void test6() {// Optional中值为null时(获取到设置的默认值)Optional<String> optionalOne = Optional.ofNullable(null);String result = optionalOne.orElseGet(() -> "默认值一");System.out.println(result); // 输出:默认值一// Optional中值不为null时(获取Optional中设置的值)Optional<String> optionalTwo = Optional.ofNullable("你好!");String result2 = optionalTwo.orElseGet(() -> "默认值二");System.out.println(result2); // 输出:你好!}
3.2.orElseThrow
orElseThrow(Supplier<? extends X> exceptionSupplier)
获取Optional中值为null时抛出我们自定义的异常,反之Optional中值不为null时就获取其Optional中具体的值;
/*** 安全获取值* orElseThrow*/private static void test7() throws Throwable {// Optional中值不为null时获取Optional中设置的值Optional<String> optionalOne = Optional.ofNullable("你好!");String resultOne = optionalOne.orElseThrow((Supplier<Throwable>) () -> new RuntimeException("获取值为null!"));System.out.println(resultOne);// Optional中值为null时抛出我们自定义的异常Optional<String> optionalTwo = Optional.ofNullable(null);String resultTwo = optionalTwo.orElseThrow((Supplier<Throwable>) () -> new RuntimeException("获取值为null!"));}
4.filter函数过滤存放在Optional中数据
使用filter方法对Optional中数据进行过滤;
例:
使用filter方法过滤Optional对象中封装的Author对象数据;
/*** filter函数过滤Optional中数据* 使用filter方法过滤Optional对象中封装的Author对象** 方法最后输出:* 作者:张学友年龄大于18岁!*/private static void test8() {// 创建Author对象Author author = new Author(1L,"张学友",60,"香港歌手",null);// Author对象包装为Optional对象Optional<Author> optionalAuthor = Optional.ofNullable(author);// 调用Optional对象的filter方法过滤数据optionalAuthor = optionalAuthor.filter(author1 -> author1.getAge() > 18);// 过滤后的数据调用ifPresent方法判断Optional对象中是否存在数据(存在则打印author对象)optionalAuthor.ifPresent(authorObj -> System.out.println("作者:" + authorObj.getName() + "年龄大于18岁!")); // 会输出// 调用Optional对象的filter方法过滤数据optionalAuthor = optionalAuthor.filter(author1 -> author1.getAge() > 88);// 过滤后的数据调用ifPresent方法判断Optional对象中是否存在数据(存在则打印author对象)optionalAuthor.ifPresent(authorObj2 -> System.out.println("作者:" + authorObj2.getName() + "年龄大于88岁!")); // 不会输出}
5.isPresent函数判断Optional中是否存在数据
使用isPresent方法判断Optional中是否存在数据。为空返回false非空返回true。相较于ifPresent方法更推荐使用ifPresent方法;
推荐ifPresent方法原因:
使用ifPresent的好处在于该方法内部会自行判断Optional对象中是否有数据,有数据才会执行后续操作;无数据则不执行后续消费操作;不像上面的isPresent方法拿取到返回值后还需程序员自行判断Optional对象中是否有数据,根据判断结果再执行后续消费代码;
/*** isPresent函数判断Optional对象中是否存在数据* 存在:true* 不存在:false*/private static void test9() {// 创建Author对象Author author = new Author(1L,"张学友",60,"香港歌手",null);// Author对象包装为Optional对象Optional<Author> optionalAuthor = Optional.ofNullable(author);/** isPresent方法使用演示 */boolean flag = optionalAuthor.isPresent();if(flag){ // Optional中存在数据System.out.println("Optional中存在数据!");// 因为上面使用isPresent方法已经判断Optional对象中已经存在数据,所以此处使用get方法获取里面的数据不会出现NoSuchElementException异常Author authorObj = optionalAuthor.get();System.out.println(authorObj);}else { // Optional中不存在数据System.out.println("Optional中不存在数据!");}/*** ifPresent方法使用演示* 使用ifPresent的好处在于该方法内部会自行判断Optional对象中是否有数据,有数据才会执行后续操作;无数据则不执行后续消费操作;* 不像上面的isPresent方法拿取到返回值后还需程序员自行判断Optional对象中是否有数据,根据判断结果再执行后续消费代码;* */optionalAuthor.ifPresent(author1 -> System.out.println("ifPresent方法输出的Author数据:" + author1));}
6.map函数对Optional中数据进行数据转换
Optional提供了map可以对数据进行转换,并且转换得到的数据也还是被Optional包装好的;
例:
获取作家的书籍集合;
/*** map函数将Optional对象中Author数据转换为书籍集合;*/private static void test10() {// 创建Author对象Author author = new Author(1L,"张学友",60,"香港歌手",null);// 构造作者书籍集合List<Book> books = new ArrayList<Book>();books.add(new Book(1L, "刀的两侧是光明与黑暗", "哲学,爱情", 88, "用—把刀划分了爱恨"));author.setBooks(books);// 将Author对象包装为Optional对象Optional<Author> optionalAuthor = Optional.ofNullable(author);// map方法将原本Optional对象中的Author对象转换为Book集合(map方法返回的仍是一个Optional对象)Optional<List<Book>> optionalBookList = optionalAuthor.map(author1 -> author1.getBooks());// optionalBookList中存在数据则将其数据打印出来optionalBookList.ifPresent(books1 -> System.out.println(books1));}