Java 知识点整理 Optional 的使用
2020/1/30 17:11:34
本文主要是介绍Java 知识点整理 Optional 的使用,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!
前言
开发相关知识点整理,内容来自我的个人网站笔记,和收集参考的资料,由于是发在社区,整理了排版和可读性,对于内容我尽量做到是经过验证的,以免误人子弟。当然本人能力有限,如有错误或疑问,欢迎一起讨论和指正(有些内容也是我参考别人的,如有侵权,请联系我,一般我会注明转载和参考原文)
1、什么是Optional?
一句话概括: 它是一个容器,用来包装对象,解决NullPointerException异常的
2、如何创建Optional对象?或者说如何用Optional来包装对象或null值?
-
static Optional empty() :用来创建一个空的Optional
-
static Optional of(T value) :用来创建一个非空的Optional
-
static Optional ofNullable(T value) :用来创建一个可能是空,也可能非空的Optional
其实上面这三个方法,看一下源码就很清晰了,比如of
// 方法 public static <T> Optional<T> of(T value) { return new Optional<>(value); } // 构造器 private Optional(T value) { this.value = Objects.requireNonNull(value); } // Objects对象的requireNonNull方法 public static <T> T requireNonNull(T obj) { if (obj == null) throw new NullPointerException(); return obj; } 复制代码
of方法创建Optional对象,并对传入值做NullPointerException异常判断,所以,当你传递一个null值的时候,就会触发异常了
再看看empty方法
// 方法 public static<T> Optional<T> empty() { @SuppressWarnings("unchecked") Optional<T> t = (Optional<T>) EMPTY; return t; } // 静态常量 private static final Optional<?> EMPTY = new Optional<>(); // 常量 private final T value; // 构造器 private Optional() { this.value = null; } 复制代码
一开始就定义了一个Optional<?> EMPTY
的对象,并且构造函数使用默认的,value为空。empty只是做了泛型的转换
剩下的ofNullable就更简单了,通过传递的值决定使用of还是empty
public static <T> Optional<T> ofNullable(T value) { return value == null ? empty() : of(value); } 复制代码
Optional类的源码还是比较简单的,代码很少,通过成员变量和构造方法的解读,相信你已经理解了of,empty,ofNullable
3、如何使用Optional类?
最正确的做法就是对需要做NullPointerException异常判断的对象,把它包装成Optional类,然后指明对象不存在的时候,应该怎么做,下面来看一下几种常见的用法
1. orElse
public class OptionalTest { public static void main(String[] args) { HashMap<Integer, User> userHashMap = new HashMap<>(); userHashMap.put(1, new User(1, "Xiao Ming")); userHashMap.put(2, new User(2, "Xiao Zhi")); userHashMap.put(3, null); UserUtil userUtil = new UserUtil(userHashMap); // 这个工具类只是为了填充数据的,不要在意这些细节,getUserByUserId方法能返回User对象 // 包装了User对象,并且使用orElse指明了对象不存在的时候应该返回指定的值,也就是new User(1, "Xiao Bai") User user = Optional .ofNullable(UserUtil.getUserByUserId(2)) .orElse(new User(1, "Xiao Bai")); } } // 工具类,随便写的,通过hashMap模拟查询用户 public class User { public Integer id; public String name; public User(Integer id, String name) { this.id = id; this.name = name; } } class UserUtil { public static HashMap<Integer, User> hashMap; UserUtil(HashMap<Integer, User> hashMap) { UserUtil.hashMap = hashMap; } public static User getUserByUserId(Integer id) { User user = hashMap.get(id); System.out.println(user); return user; } } 复制代码
2. orElseGet
和 orElse 不同,它的参数接受一个lambda表达式
User user = Optional .ofNullable(UserUtil.getUserByUserId(2)) .orElseGet(() -> new User(1, "Xiao Bai")); 复制代码
3. orElseThrow
同理,传递一个lambda表达式异常(注意啊,方法是限定了参数的,触发异常就用orElseThrow,不能用orElseGet)
User user = Optional .ofNullable(UserUtil.getUserByUserId(2)) .orElseThrow(()-> new AssertionError("AssertionError")); 复制代码
4. map
调用map后,如果当前 Optional 为 Optional.empty,则依旧返回 Optional.empty;否则返回一个新的 Optional,该 Optional 包含的是:函数 mapper 在以 value 作为输入时的输出值
比如下面的例子,第一次调用map后,获取的是name,传递给下一个map的值相当于Optional.ofNullable(name)
String user = Optional.ofNullable(UserUtil.getUserByUserId(1)) .map(user1 -> user1.name) .map(String::toLowerCase) .orElse("123"); System.out.println(user); // 方法 public<U> Optional<U> map(Function<? super T, ? extends U> mapper) { Objects.requireNonNull(mapper); if (!isPresent()) return empty(); else { return Optional.ofNullable(mapper.apply(value)); } } 复制代码
这个操作可以用在对对象做多次操作的场景下,并且保证为空的时候返回指定的值,比如先获取用户的名称,再获取用户的电话,做一下判断后,再通过电话查询到其它的数据,然后继续...,最后如果某一环节出现异常,那就返回orElse定义的对象
5. flatMap
flatMap 方法与 map 方法的区别在于,map 方法参数中的函数 mapper 输出的是值,然后 map 方法会使用 Optional.ofNullable 将其包装为 Optional;而 flatMap 要求参数中的函数 mapper 输出的就是 Optional
即 .flatMap(user -> Optional.of(user.name()))
6. filter
都是差不多的套路,这次我们先看源码,可以发现同样是接受lambda表达式,并且要是一个Boolean返回值的,如果本次操作的optional是empty的,就返回本身
public Optional<T> filter(Predicate<? super T> predicate) { Objects.requireNonNull(predicate); if (!isPresent()) return this; else return predicate.test(value) ? this : empty(); } // 函数式接口部分代码,可以看到test是要求返回Boolean类型的 @FunctionalInterface public interface Predicate<T> { /** * Evaluates this predicate on the given argument. * * @param t the input argument * @return {@code true} if the input argument matches the predicate, * otherwise {@code false} */ boolean test(T t); } // 例子 String name = Optional.ofNullable(UserUtil.getUserByUserId(1)) .filter(user -> user.id == 2) .map(user -> user.name) .orElse("abc"); System.out.println(name); 复制代码
通过观察源码,我们可以看到,很多为空的都会返回empty,这让各个操作都能够互相调用
总结
Optional是一个比较简单的类,推荐直接阅读源码,通过简单的包装,很优雅的解决的空指针问题,以前谷歌Guava库就实现了,后面Java8正式把规范加到 java.util.Optional
类中。
另外,上面的做法是对于程序内的,如果是web开发,参数校验,请使用Hibernate-Validator即可,作为一个合格的后端,我不会让前端挑刺的😀
这篇关于Java 知识点整理 Optional 的使用的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!
- 2024-09-28AI给的和自己写的Python代码,都无法改变输入框的内容,替换也不行
- 2024-09-27Sentinel配置限流资料:新手入门教程
- 2024-09-27Sentinel配置限流资料详解
- 2024-09-27Sentinel限流资料:新手入门教程
- 2024-09-26Sentinel限流资料入门详解
- 2024-09-26Springboot框架资料:初学者入门教程
- 2024-09-26Springboot框架资料详解:新手入门教程
- 2024-09-26Springboot企业级开发资料:新手入门指南
- 2024-09-26SpringBoot企业级开发资料新手指南
- 2024-09-26Springboot微服务资料入门教程