一文教你用好Optional类,再也不怕空指针异常了

互联网行业更新换代实在是太快了,不看不知道,一看吓一跳,Java不知不觉就已经更新到JDK20了,不得不说,那个团队是真的强悍。

目前大部分公司仍然使用的是JDK8这个主流版本,对于JDK7而言,它就是一个重大革新版本,其中引入了太多的黑科技,Optional就是其中之一。

Optional是一个容器对象,可以往里面放置一个null值或者非null值。如果值为null,则返回一个空对象。如果值不为null,isPresent()将返回true,get()则获取该值。引入这么一个类,其实就是为了更好地解决业界臭名昭著的空指针异常(NullPointerException),避免繁琐的null值检查,让书写代码变得更加简洁流畅。

1,构建Optional对象

1empty()

返回一个空的Optional对象,对空对象调用get()方法会报NoSuchElementException异常

PS:这个方法感觉有点鸡肋,虽说是个容器对象,但你只能放一个值,而且API中也没有提供所谓的插值方法,那我为什么要构建一个空的、取值还报错的对象呢。

        Optional op=Optional.empty();
        Object o = op.get();

在这里插入图片描述

2of(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);

在这里插入图片描述

3ofNullable(T value)

构造一个可能含null值的Optional对象,如果value为null,则返回一个空对象。这个方法有点意思,这也是这个类的精髓。

2,判断值存在

1isPresent()

判断内部值是否存在,返回true或false。

PS:有点鸡肋,这里返回一个boolean值,且打断了链式操作,后续还得用if-else做逻辑判断。

        Optional<User> op = Optional.ofNullable(map.get("k2"));
        boolean present = op.isPresent();
        System.out.println(present);

2ifPresent(Consumer<? super T> consumer)

判断内部值是否存在,如果存在则消费这个值,不存在则什么都不做,没有返回值。这个方法的精髓之处就是既不妨碍对内部值的后续处理,又完美得避开了空指针异常。如代码所示,map中k2处的值我们不知道是否为空,如果是空,那我们什么都不做,如果非空,我们才消费这个元素。这里很明显的好处就是我们省略了if语句块。

Optional<User> op = Optional.ofNullable(map.get("k2"));
op.ifPresent(element-> System.out.println(element.getName()));

3,获取内部值

1get()

获取内部值,前面有介绍,对空对象调用get()方法会报NoSuchElementException异常。

PS:可以用,但是一般不直接调用,而是先判断Optional对象的值是否存在,存在则调用get()获取。

2orElse(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());

在这里插入图片描述

3orElseGet(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());

4orElseThrow(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()

1map(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);

2flatMap(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);

3filter(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);

在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/qq_36756227/article/details/129909763