函数式编程Stream 流(三)--Optional
4.1概述
我们在编写代码的时候出现最多的就是空指针异常,所以在很多情况下我们需要做各种非空的判断
例如:
Author author= new Author(); if(author!=null){ System.out.println(author.getName()); }
尤其是对象中的属性还是一个对象的情况下。这种判断会更多。
而过多的判断语句会让我们的代码显得臃肿不堪;
所以在JDK8中,引入了Optional ,养成使用Optional的习惯后,我们可以写出更优雅的代码来避免空指针异常。
并且在很多函数式编程相关的API中都用到了Optional,如果不会使用Optional 也会对函数式编程的学习造成影响;
4.2使用
4.2.1创建对象
Optional就好像是一个包装类,可以把我们的具体数据封装在Optional对象内部。然后我们去使用Optional中封装的方法操作封装进去的数据就可以非常优雅的避免空指针异常
1.Optional.ofNullable(author)--建议使用
我们一般使用Optional的静态方法Optional.ofNullable()来把数据封装成一个Optional对象。无论传入的参数是否为null都不会出现问题;
Author author =getAuthor(); // if(author!=null) System.out.println(author = + author.getName()); Optional<Author> authorOptional= Optional.ofNullable(author); authorOptional.ifPresent(new Consumer<Author>() { @Override public void accept(Author author) { String name = author.getName(); System.out.println(name = + name); } });
这里我们可能觉得用一串更长的代码来尽心判断null异常不是更麻烦吗?so,我们改造一下getAuthor方法,让其返回值就是封装好的Optional的话,我们在使用时候就会方便很多;
而且在实际的开发中,我们很多的数据都是直接从数据库去查询获取的,Mybatis从3.5版本已经开始支持Optional;
我们可以直接把dao方法的返回值类型定义成Optional类型,Mybatis会自己把数据封装成Optional对象返回。封装的过程也不需要我们自己操作;
public static void main(String[] args) { Optional<Author> author = getAuthor(); author.ifPresent(new Consumer<Author>() { @Override public void accept(Author author) { System.out.println(author = + author.getName()); } }); } private static Optional<Author> getAuthor() { Author author = new Author(1L, 蒙多, 33, 一个从菜刀中明悟这里的祖安人, null); return Optional.ofNullable(author); }
2.Optional.of(author)
如果你确定对象不是空,那么可以使用Optional的静态方法Optional.of()来把数据封装成Optional对象
Optional<Author> author = getAuthor();` Optional<Author> auhtorOptional =Optional.of(author);`
但是一定要注意,如果使用of的时候传入的参数必须不为null(可以尝试下会出现什么结果)--仍然空指针
3.Optional.empty()
如果一个方法的返回值类型是Optional,并且如果我们经过判断,返现末次计算得到的返回值就是null.这个时候就需要把null封装成Optional 对象返回,
这个时候我们可以使用Optional的静态方法Optional.empty()来进行封装;
return author==null? Optional.empty():Optional.of(author);
4.2.2安全消费值
我们获取到一个Optional对象后肯定需要对其中的数据进行使用。这时候我们可以使用其对象.isPresent()方法来消费其中的值;。
这个方法会判断其内封装的数据是否为空,不为空时才会执行具体的消费代码。这样使用起来就更加的安全了
public static void main(String[] args) { Optional<Author> optionalAuthor = Optional.ofNullable(getAuthor()); optionalAuthor.ifPresent(new Consumer<Author>() { @Override public void accept(Author author) { System.out.println(author = + author.getName()); } }); }
4.2.3获取值
如果我们想获取值自己进行处理可以使用对象.get()方法获取,但是不推荐,因为当Optional内部的数据为null的时候会出现异常,返回值是空,再处理就找不到元素异常
Optional<Author> optionalAuthor = Optional.ofNullable(getAuthor()); Author author1 = optionalAuthor.get();
4.2.4安全获取值
如果我期望安全的获取值,我们不推荐使用get方法,而是使用Optional提供的一下方法
- orElseGet
获取数据并且设置数据为空时的默认值。
如果数据不为空就能获取到该数据。如果为空则则根据你传入的参数来创建一个对象代替null作为默认值返回
Optional<Author> optionalAuthor = Optional.ofNullable(getAuthor()); Author author2 = optionalAuthor.orElseGet(new Supplier<Author>() { @Override public Author get() { return new Author(); } });
- orElseThrow
获取数据,如果数据不为空就能获取到该数据。如果为空则根据你传入的参数来创建异常并且抛出
Optional<Author> optionalAuthor = Optional.ofNullable(getAuthor()); try { optionalAuthor.orElseThrow(new Supplier<Throwable>() { @Override public Throwable get() { return new RuntimeException(author 为空); } }); } catch (Throwable throwable) { throwable.printStackTrace(); }
4.2.5过滤
我们可以使用filter 方法对数据进行过滤。如果原本是有数据的,但是不符合判断,也会变成一个无数据的Optional对象,剔除掉不符合要求的对象,返回Optional
Optional<Author> author = Optional.ofNullable(getAuthor()); author.filter(new Predicate<Author>() { @Override public boolean test(Author author) { return author.getAge()>100; } }).ifPresent(new Consumer<Author>() { @Override public void accept(Author author) { System.out.println(author = + author.getName()); } }); }
4.2.6判断 isPresent()/ifPresent()
我们可以使用Optional.isPresent()进行是否存在数据的判断。如果为空,返回值为false,如果不为空,返回值为true。但是这种方式并不能体现Optional的好处
所以更推荐Optional.ifPresent()方法
Optional<Author> author = Optional.ofNullable(getAuthor()); if (author.isPresent()) {//还是要写if判断,不如直接 写null System.out.println(author = + author.orElse(new Author()).getName()); }
4.2.7数据转换map()方法
Optional 还提供了map可以让我们来对数据进行转换,并且转换得到的数据也还是被Optional 封装好的,保证了我们的使用安全;
例如:我们想要获取作家的书籍集合。。类似Stream的map方法
Optional<Author> author = Optional.ofNullable(getAuthor()); Optional<List<Book>> books = author.map(new Function<Author, List<Book>>() { @Override public List<Book> apply(Author author) { return author.getBooks(); } }); books.ifPresent(new Consumer<List<Book>>() { @Override public void accept(List<Book> books) { books.forEach(new Consumer<Book>() { @Override public void accept(Book book) { System.out.println(book = + book.getName()); } }); } }); }