Java基础知识11--Optional类
1.Optional概念
java.util.Optional<T>
类是一个封装了Optional
值的容器对象,Optional
值可以为null
,如果值存在,调用isPresent()
方法返回true
,调用get()
方法可以获取值。
Optional 是个容器:它可以保存类型T的值,或者仅仅保存null。Optional提供很多有用的方法,这样我们就不用显式进行空值检测。
Optional 类的引入很好的解决空指针异常。
以下是 java.util.Optional<T> 类的声明:
public final class Optional<T> extends Object
2.为什么要使用Optional
目的:避免使用null
检查
作为Java开发人员,几乎所有人都遇到过NullPointerException
异常,大多数人遇到NullPointerException
异常时都会在异常出现的地方加上if
代码块来判断值不为空,比如下面的代码:
public void bindUserToRole(User user) { if (user == null) { return; } String roleId = user.getRoleId(); if (roleId == null) { return; } Role = roleDao.findOne(roleId); if (role != null) { role.setUserId(user.getUserId()); roleDao.save(role); } }
方法内有三个不同的返回点,出错后调试也不容易,你都不知道是那个值导致了NullPointerException
异常。
基于上面的原因,Java 8中引入了一个新的类Optional
,用以避免使用null
值引发的种种问题。
Optional<String> roleOpt = Optional.ofNullable(user).map(User::getRoleId); if(roleOpt.isPresent()){ .... }
3.创建Optional
对象
Optional
类提供类三个方法用于实例化一个Optional
对象,它们分别为empty()
、of()
、ofNullable()
,这三个方法都是静态方法,可以直接调用。
(1)empty()
方法
empty()
方法用于创建一个没有值的Optional
对象:
Optional<String> emptyOpt = Optional.empty();
empty()
方法创建的对象没有值,如果对emptyOpt
变量调用isPresent()
方法会返回false
,调用get()
方法抛出NullPointerException
异常。
(2)of()
方法
of()
方法使用一个非空的值创建Optional
对象:
String str = "Hello World";
Optional<String> notNullOpt = Optional.of(str);
(3)ofNullable()
方法
ofNullable()
方法接收一个可以为null
的值:
Optional<String> nullableOpt = Optional.ofNullable(str);
如果str
的值为null
,得到的nullableOpt
是一个没有值的Optional
对象。
若是集合类型:
Optional<List<Student>> studentList1 = Optional.ofNullable(studentList);
(4)of()
和ofNullable()
方法辨析
当你很确定一个对象不可能为null
的时候,应该使用of()
方法,否则,尽可能使用ofNullable()
方法,比如:
public static void method(Role role) { // 当Optional的值通过常量获得或者通过关键字new初始化,可以直接使用of()方法 Optional<String> strOpt = Optional.of("Hello World"); Optional<User> userOpt = Optional.of(new User()); // 方法参数中role值不确定是否为null,使用ofNullable()方法创建 Optional<Role> roleOpt = Optional.ofNullable(role); }
4.map()方法提取Optional
对象中的值
如果我们要获取User
对象中的roleId
属性值,常见的方式是直接获取:
String roleId = null; if (user != null) { roleId = user.getRoleId(); }
使用Optional
中提供的map()
方法可以以更简单的方式实现:
Optional<User> userOpt = Optional.ofNullable(user);
Optional<String> roleIdOpt = userOpt.map(User::getRoleId);
List<String> paramNameList = Optional.ofNullable(ruleProcessParaList).orElse(new ArrayList<>()).stream().map(PmRuleProcessPara::getAttrCode).collect(Collectors.toList());
map()
方法与Stream API中的map()
一样,类似于映射操作,将原始类型映射为一个新的类型。
5.使用orElse()
方法获取值
源码:
public T orElse(T var1) { return this.value != null ? this.value : var1; }
orElse()
:如果有值就返回T,否则返回一个给定的值作为默认值;
案例1:
return str != null ? str : "Hello World"
上面的代码表示判断字符串str
是否为空,不为空就返回,否则,返回一个常量。使用Optional
类可以表示为:
return strOpt.orElse("Hello World")
案例2:
public class OptionalTest { public static void main(String[] args) { List<Student> studentList=new ArrayList<>(); Student student1=new Student(); student1.setAge(10); student1.setName("lucky"); Student student2=new Student(); student2.setAge(12); student2.setName("linda"); studentList.add(student1); studentList.add(student2); Optional<List<Student>> studentList1 = Optional.ofNullable(studentList); List<Student> studentList2 = Optional.ofNullable(studentList).orElse(new ArrayList<>()); List<Integer> collect = Optional.ofNullable(studentList).orElse(new ArrayList<>()).stream().map(Student::getAge).collect(Collectors.toList()); System.out.println("hello"); } }
debug截图:
6.ifPresent()方法
如果值存在则使用该值调用 consumer , 否则不做任何事情。示例如下
public void ifPresent(Consumer<? super T> var1) { if (this.value != null) { var1.accept(this.value); } }
代码实例:
Optional<String> optional=Optional.ofNullable("zh");
optional.ifPresent(s1 -> System.out.println(s1));
典型应用1:将map转为字符串str
public static void main(String[] args) { Map<String, Object> paramsMap = new HashMap<>(); paramsMap.put("key1", "One"); paramsMap.put("key2", "Two"); StringBuffer sb=new StringBuffer(); Optional.ofNullable(paramsMap.entrySet()).ifPresent(paramSet->{ paramSet.forEach((entry)->{ sb.append(entry.getKey()).append("=").append(entry.getValue()).append("&"); }); }); System.out.println(sb); } }
debug断点:
控制台输出:
key1=One&key2=Two&
典型应用2:
public class OptionalTest { public static void main(String[] args) { List<Person> personList=new ArrayList<>(); Person person1=new Person(); person1.setName("lucky"); person1.setAge(27); Person person2=new Person(); person2.setName("linda"); person2.setAge(25); personList.add(person1); personList.add(person2); Optional.ofNullable(personList).ifPresent(persons->{ persons.forEach(person->{ person.setName("tom"); }); }); System.out.println(personList); } }
控制台输出:
[Person(name=tom, age=27), Person(name=tom, age=25)]
debug发现:personList地址与persons地址一致
源码执行逻辑分析:
public final class Optional<T> { private static final Optional<?> EMPTY = new Optional(); private final T value; private Optional() { this.value = null; }private Optional(T var1) { this.value = Objects.requireNonNull(var1); } public static <T> Optional<T> of(T var0) { return new Optional(var0); } public static <T> Optional<T> ofNullable(T var0) { return var0 == null ? empty() : of(var0); }public boolean isPresent() { return this.value != null; } public void ifPresent(Consumer<? super T> var1) { if (this.value != null) { var1.accept(this.value); } } ...... }
阅读源码可见,ofNullable方法里调用了of方法,of方法里调用了构造方法。
ifPresent方法里调用了Consumer类里的accept方法
参考文献:https://lw900925.github.io/java/java8-optional.html
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
· 没有源码,如何修改代码逻辑?
· 一个奇形怪状的面试题:Bean中的CHM要不要加volatile?
· 分享4款.NET开源、免费、实用的商城系统
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
· 上周热点回顾(2.24-3.2)