一、简述
Optional类是java8中引入的一个非常有用的类,主要用处是解决编程中的空指针异常,本质上,这是一个包含有可选值的包装类,这意味着 Optional 类既可以含有对象也可以为空。Optional 是 Java 实现函数式编程的强劲一步,并且帮助在范式中实现。
二、场景
在java8之前,任何访问对象方法或属性的调用都有可能导致空指针异常,例如:
String isocode = user.getAddress().getCountry().getIsocode().toUpperCase();
这行代码如果我们需要确保不触发异常,我们就要写成:
if (user != null) {
Address address = user.getAddress();
if (address != null) {
Country country = address.getCountry();
if (country != null) {
String isocode = country.getIsocode();
if (isocode != null) {
isocode = isocode.toUpperCase();
}
}
}
}
这样看起来太繁琐了,而且看起来很low,那么如何才能简洁的实现以上判断呢?
三、Optional容器类的常用方法
Optional.of(T t):创建一个Optional实例
Optional.empty():创建一个空的Optional实例
Optional.ofNullable(T t):若t不为null,创建Optional实列,否则创建空实例
isPresent():判断是否包含值
orElse(T t):如果调用对象包含值,返回该值,否则返回t
orElseGet(Supplier s):如果调用对象包含值,返回该值,否则返回s获取的值
map(Function f):如果有值对其处理,并返回处理后的Optional,否则返回Optional.empty()
flatMap(Function mapper):与map类似,要求返回值必须是Optional
1.创建Optional实例
使用empty()创建空实例
Optional<User> emptyOpt = Optional.empty();
尝试访问emptyOpt变量的值会导致NoSuchElementException
使用of()或ofNullable()方法创建包含值的Optional,不同之处在于:如果你把 null 值作为参数传递进去,of() 方法会抛出 NullPointerException
Optional<User> opt1 = Optional.of(user);
Optional<User> opt1 = Optional.ofNullable(user);
2.访问Optional对象的值
使用get()方法获取Optional的值
Optional<User> opt1 = Optional.of(user);
User tmp = opt1.get();
3.返回默认值
orElse()方法可以在创建实例时就指定返回的默认值
User user = null;
User user2 = new User("[email protected]", "1234");
User result = Optional.ofNullable(user).orElse(user2);
因为user是空,所以此时我们想获取result的值的话会得到user2
我们也可以使用orElseGet(),如果没有值,它会执行作为参数传入的 Supplier(供应者) 函数式接口,并将返回其执行结果
User result = Optional.ofNullable(user).orElseGet( () -> user2);
不同的是使用orElse的话无论创建的值是否为空,都会orElse里的代码,如果里面有创建新的实例,这会对性能产生很大影响
另外我们可以使用orElseThrow(),它会在对象为空的时候抛出异常,而不是返回备选的值
User result = Optional.ofNullable(user)
.orElseThrow( () -> new IllegalArgumentException());
此时如果user为空,会抛出我们定义的异常IllegalArgumentException
4.转换值
我们可以使用map方法,将 Optional里的元素进行转换
User user = new User("[email protected]", "1234");
String email = Optional.ofNullable(user)
.map(u -> u.getEmail()).orElse("[email protected]");
注意无论是user为null,还是user里的Email为空,都会触发返回orElse里的默认值,这也就Optional的map操作的链式调用的精髓,我们可以不断的接着写map,无需一次次地判断是否为空
5.过滤值
filter()接受一个Predicate参数,返回测试结果为 true 的值
用法和stream的filter一模一样,例如我们可以检查用户的邮箱是否带@
User user = new User("[email protected]", "1234");
Optional<User> result = Optional.ofNullable(user)
.filter(u -> u.getEmail() != null && u.getEmail().contains("@"));
6.对原来if的改进
对于User类我们对其进行重构,使其getter方法返回Optional类
public class User {
private Address address;
public Optional<Address> getAddress() {
return Optional.ofNullable(address);
}
// ...
}
public class Address {
private Country country;
public Optional<Country> getCountry() {
return Optional.ofNullable(country);
}
// ...
}
之前冗杂的if判断我们就可以改成这样:
String result = Optional.ofNullable(user)
.flatMap(u -> u.getAddress())
.flatMap(a -> a.getCountry())
.map(c -> c.getIsocode())
.orElse("default");
也可以简写成这样:
String result = Optional.ofNullable(user)
.flatMap(User::getAddress)
.flatMap(Address::getCountry)
.map(Country::getIsocode)
.orElse("default");
四、代码示例
public static void main(String[] args) {
test1();
}
//1、Optional.of(T t):创建一个Optional实例
public static void test1() {
Optional<User> op = Optional.of(new User());
User emp = op.get();
System.out.println(emp);
}
运行结果:
User{
id=null, name='null', sex='null', age=null, createDt='null', updateDt='null'}
//2、Optional.empty():创建一个空的Optional实例
public static void test2() {
Optional<User> op = Optional.empty();
System.out.println(op.get());
}
运行结果:
Exception in thread "main" java.util.NoSuchElementException: No value present
at java.util.Optional.get(Optional.java:135)
at org.sang.test.OptionalDemo.test2(OptionalDemo.java:28)
at org.sang.test.OptionalDemo.main(OptionalDemo.java:14)
语法说明
标题文本样式列表图片链接目录代码片表格注脚注释自定义列表LaTeX 数学公式插入甘特图插入UML图插入Mermaid流程图插入Flowchart流程图插入类图快捷键
代码片复制
下面展示一些 内联代码片
。
// A code block
var foo = 'bar';
//3、Optional.ofNullable(T t):若t不为null,创建Optional实列,否则创建空实例
public static void test3() {
Optional<User> op = Optional.ofNullable(null); //不能传null
if (op.isPresent()) {
System.out.println(op.get());
// System.out.println(op1.get());
}
System.out.println("-------------------------------------------------------");
User emp = op.orElse(new User(1,"zhangsan", "man",18));
System.out.println(emp);
System.out.println("-------------------------------------------------------");
User emp1 = op.orElseGet(() -> new User());
System.out.println(emp1);
}
运行结果:
User{
id=1, name='zhangsan', sex='man', age=18, createDt='null', updateDt='null'}
-------------------------------------------------------
User{
id=null, name='null', sex='null', age=null, createDt='null', updateDt='null'}
public static void test4() {
Optional<User> op = Optional.ofNullable(new User(1,"zhangsan", "man",18));
// Optional<String> s = op.map((e) -> e.getName());
// System.out.println(s.get());
//多一步判空
Optional<String> s = op.flatMap((e) -> Optional.of(e.getName()));
System.out.println(s.get());
}
运行结果:
zhangsan