概述
在编写代码的时候出现最多的就是空指针异常。所以在很多情况下我们需要做各种非空的判断。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));
}