互联网行业更新换代实在是太快了,不看不知道,一看吓一跳,Java不知不觉就已经更新到JDK20了,不得不说,那个团队是真的强悍。
目前大部分公司仍然使用的是JDK8这个主流版本,对于JDK7而言,它就是一个重大革新版本,其中引入了太多的黑科技,Optional就是其中之一。
Optional是一个容器对象,可以往里面放置一个null值或者非null值。如果值为null,则返回一个空对象。如果值不为null,isPresent()
将返回true,get()
则获取该值。引入这么一个类,其实就是为了更好地解决业界臭名昭著的空指针异常(NullPointerException),避免繁琐的null值检查,让书写代码变得更加简洁流畅。
1,构建Optional对象
1,empty()
返回一个空的Optional对象,对空对象调用get()
方法会报NoSuchElementException异常
PS:这个方法感觉有点鸡肋,虽说是个容器对象,但你只能放一个值,而且API中也没有提供所谓的插值方法,那我为什么要构建一个空的、取值还报错的对象呢。
Optional op=Optional.empty();
Object o = op.get();
2,of(T value)
构造一个含非null值的Optional对象,注意value一定不能为空,否则报NullPointerException异常
PS:有点鸡肋,Optional的特点就是既可能含null也可能含非null值,你这里又限定了必须给我一个非null值,这是什么意思,那我岂不是构造Optional时还得对value进行非空检查呢。
User user=new User(1,"shengr");
Map<String, User> map = new HashMap<>();
map.put("k1",user);
Optional<User> op = Optional.of(map.get("k2"));
User result = op.get();
System.out.println(result);
3,ofNullable(T value)
构造一个可能含null值的Optional对象,如果value为null,则返回一个空对象。这个方法有点意思,这也是这个类的精髓。
2,判断值存在
1,isPresent()
判断内部值是否存在,返回true或false。
PS:有点鸡肋,这里返回一个boolean值,且打断了链式操作,后续还得用if-else做逻辑判断。
Optional<User> op = Optional.ofNullable(map.get("k2"));
boolean present = op.isPresent();
System.out.println(present);
2,ifPresent(Consumer<? super T> consumer)
判断内部值是否存在,如果存在则消费这个值,不存在则什么都不做,没有返回值。这个方法的精髓之处就是既不妨碍对内部值的后续处理,又完美得避开了空指针异常。如代码所示,map中k2处的值我们不知道是否为空,如果是空,那我们什么都不做,如果非空,我们才消费这个元素。这里很明显的好处就是我们省略了if语句块。
Optional<User> op = Optional.ofNullable(map.get("k2"));
op.ifPresent(element-> System.out.println(element.getName()));
3,获取内部值
1,get()
获取内部值,前面有介绍,对空对象调用get()方法会报NoSuchElementException异常。
PS:可以用,但是一般不直接调用,而是先判断Optional对象的值是否存在,存在则调用get()
获取。
2,orElse(T other)
获取内部值,如果内部值不存在则返回T。这个方法的好处就是,如果内部值不存在,我也不报错,而是构建一个默认值返回给你。
Optional<User> op = Optional.ofNullable(map.get("k2"));
User user1 = op.orElse(new User(999, "default-value"));
System.out.println(user1.toString());
3,orElseGet(Supplier<? extends T > other)
获取内部值,如果内部值不存在则调用supplier函数构建一个值。这个方法和orElse类似,区别在于orElse传入的是默认值,orElseGet可以接收一个lambda表达式生成默认值。
Optional<User> op = Optional.ofNullable(map.get("k2"));
User user1 = op.orElseGet(()->new User(999,"default-value"));
System.out.println(user1.toString());
4,orElseThrow(Supplier<? extends X> exceptionSupplier)
获取内部值,如果内部值不存在则调用Supplier函数构建一个异常对象抛出。
Optional<User> op = Optional.ofNullable(map.get("k2"));
User user1 = op.orElseThrow(()->new Exception("元素为空"));
System.out.println(user1.toString());
4,链式操作
所谓的链式操作就是,对Optional对象调用方法,返回的还是一个Optional对象,这样你就可以一直点点点…构建一个复杂的链式转换操作。java8中提供了三个转换方法,分别是map()
,flatMap()
,filter()
1,map(Function<? super T,? extends U> mapper)
转换方法,在内部值不为null的情况下,将内部值转换为新的对象。如果内部值为null,则返回一个空的Optional对象。
//k1处有值,最终结果打印的是k1处的user的name值
String str = Optional.ofNullable(map.get("k1"))
.map(value -> value.getName())
.orElse("内部值为null");
System.out.println(str);
//k2处没有值,打印的是"内部值为null"
String str = Optional.ofNullable(map.get("k2"))
.map(value -> value.getName())
.orElse("内部值为null");
System.out.println(str);
2,flatMap(Function<? super T,Optional> mapper)
平铺转换,在内部值不为null的情况下,将内部值包装成一个新的Optional对象。flatMap语义上和map类似,但是限定了mapper函数中返回的类型必须是Optional对象。
PS:小吐槽,有点多此一举的感觉。
//和map的写法等效
String text1 = Optional.ofNullable(map.get("k1"))
.flatMap(value -> Optional.of(value.getName()))
.orElse("内部值为null");
System.out.println(text1);
3,filter(Predicate<? super T> predicate)
过滤方法,对 Optional 中包含的值进行过滤,如果包含的值满足条件,那么还是返回这个Optional对象,否则返回空的Optional对象。
User user=new User(1,"shengr");
Map<String, User> map = new HashMap<>();
map.put("k1",user);
User result = Optional.ofNullable(map.get("k1"))
.filter(value -> value.getName().length() > 4)
.orElse(new User(999, "default-user"));
System.out.println(result.toString());
5,使用场景
案例1:改写简单if语句块
User user=map.get("k1");
if(user!=null){
System.out.println(user.getName());
}
使用Optional类改写
Optional.ofNullable(map.get("k1")).ifPresent( p -> System.out.println(p.getName()) );
案例2:非法情况抛出异常
if(user==null || user.getName()==null){
throw new Exception();
}
String name = user.getName();
改写成一行
String name = Optional.ofNullable(user).filter(p -> p.getName() != null).orElseThrow(() -> new Exception()).getName();
案例三:改写多重判空
int size=0;
if(map!=null){
User user=map.get("k1");
if(user!=null){
String name=user.getName();
if(name!=null){
size= name.length();
}
}
}
改写成一条语句
int size=Optional.ofNullable(map)
.map( p-> p.get("k1") )
.map( p->p.getName() )
.map( p->p.length() )
.orElse(0);