美文网首页
JDK8新特性之:Optional

JDK8新特性之:Optional

作者: 两句挽联 | 来源:发表于2018-08-20 20:42 被阅读0次

    痛点

    在java编码过程中,大家碰到的最多的异常是什么,我相信必然这货NullPointerException必然是排行第一的。那我们在平时编码中,有各种编码规范与其相关,比如时时的判断null,方法禁止返回null等,例如

    public void bindUserToRole(User user) {
        if (user != null) {
            String roleId = user.getRoleId();
            if (roleId != null) {
                Role role = roleDao.findOne(roleId);
                if (role != null) {
                    role.setUserId(user.getUserId());
                    roleDao.save(role);
                }
            }
        }
    }
    

    或者

    public String 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,好好的代码写成这个鸟样,或许下面的会看上去比较顺眼一点,但是大体还是一样的。
    其实我们有一种更为优雅的方式来完成上面的功能,如下

    Optional<String> roleOpt = Optional.ofNullable(user).map(User::getRoleId);
    if(roleOpt.isPresent()){
        ....
    }
    

    这样,我们仅需要对我们关心的做一次校验,省却了前面的一系列的检验操作。

    Optional的引入

    基于上述的一些原因,在JDK8中,引入了一个新的类java.util.Optional,来避免这类问题的处理。
    先看下类的说明

    A container object which may or may not contain a non-null value.If a value is present, isPresent()will return true andget() will return the value.

    这里面说明这是一个可以包含null或者非null的容器,其最基本的两个操作就是isPresent()get(),基本用起来就是这样

    if( oneOptional.isPresent() ){
         String s = oneOptional.get();
        ....
    }
    

    首先我们看下这个类中包含哪些方法,如下

    image.png

    首先,其有一个成员变量和一个定义的常量如下

       private static final Optional<?> EMPTY = new Optional<>();
       private final T value;
    

    其中value表示其封装的真实的对象,EMPTY是定义的一个表示空的常量。构造方法很很简单,两个常见的私有构造方法Optional()Optional(T),其中不带参的默认设置valuenull,带参的构造函数,不允许传null

    Optional类包含3个静态方法生成Optional对象,分别为

    • Optional<T> empty()
      生成一个空Optional对象,其valuenull
    • Optional<T> of(T value)
      调用Optional(T)构造方法,其value不允许为null
    • Optional<T> ofNullable(T value)
      Optional<T> of(T value)的差别是其传入的value允许为null

    下面简单介绍一下里面的各个方法和一些简单的使用示例

    • get()
      返回value,若为null则抛出异常NoSuchElementException
    • isPresent()
      判断当前的value是否为null
    • ifPresent(Consumer<? super T> consumer)
      该方法支持传入一个Consumer对象,当value不为null的时候调用,为null则不做任何操作,示例如下
        public void testIfPresent(){
            Optional<String> optional=Optional.of("zh");
            optional.ifPresent(new Consumer<String>() {
                @Override
                public void accept(String s) {
                    System.out.println(s);
                }
            });
        }
    

    配合lambda使用,代码更为简洁

        public void testIfPresent(){
            Optional<String> optional=Optional.of("zh");
            optional.ifPresent(s -> System.out.println(s));
        }
    
    • filter(Predicate<? super T> predicate)
      顾名思义,这个方法的作用就是filter(过滤),该方法用于过滤一个Optional对象,通过传入的Predicate对象中的一个test方法,例如
            Optional<String> optional=Optional.of("aa");
            Optional<String> optionalResult=optional.filter(s -> s.startsWith("a"));
            System.out.println(optionalResult);
    

    输出结果是

    Optional[aa]
    

    由于其返回仍是一个Optional对象,我们可以有如下较为优雅的写法

    Optional<String> optionalResult=optional.filter(s -> s.startsWith("a"))
                    .filter(s -> s.length()==2)
                    .filter(s -> s.endsWith("a"));
    
    • map(Function<? super T, ? extends U> mapper)
      此方法支持一个Function参数,在这个Function里面可以对这个Optional对象做一些操作或者改变,其返回值仍为一个Optional类型,例如
    Optional<String> optional=Optional.of("aa");
            Optional<Integer> result= optional.map(s -> s.toUpperCase())
                    .map(s->s.length());
    

    输出结果为

    Optional[2]
    

    map提供一种优雅的流式的方式来替代先前繁杂的if判断和数据处理

    • flatMap(Function<? super T, Optional<U>> mapper)
      map类似,只不过需要我们手动将方法的返回,封装成Optional对象,如
    Optional<Integer> result= optional.flatMap(s -> Optional.of(s.toUpperCase()))
                    .flatMap(s -> Optional.of(s.length()));
    

    其余功能与map一致 。

    • orElse(T other)
      这个方法较为简单,参数为一个默认值,即若valuenull,则返回默认值
            Optional<String> optional=Optional.of("aa");
            System.out.println(optional.orElse("bb"));
            Optional<String> optional1=Optional.ofNullable(null);
            System.out.println(optional1.orElse("bb"));
    

    输出为

    aa
    bb
    
    • orElseGet(Supplier<? extends T> other)
      提供一个Supplier入参,改Supplier提供一个默认值,例如
        Optional<String> optional=Optional.ofNullable(null);
        System.out.println(optional.orElseGet(() -> "aaa"));
    
    • orElseThrow(Supplier<? extends X> exceptionSupplier)
      顾名思义,若为null则抛出异常
            Optional<String> optional=Optional.ofNullable(null);
            System.out.println(optional.orElseThrow(() -> new RuntimeException()));
    

    使用场合注意

    Reports calls to java.util.Optional.get() without first checking with a isPresent() call if a value is available. If the Optional does not contain a value, get() will throw an exception.

    Optional.get() 前不事先用 isPresent() 检查值是否可用. 假如 Optional 不包含一个值, get() 将会抛出一个异常

    Reports any uses of java.util.Optional<T>, java.util.OptionalDouble, java.util.OptionalInt, java.util.OptionalLong or com.google.common.base.Optional as the type for a field or a parameter. Optional was designed to provide a limited mechanism for library method return types where there needed to be a clear way to represent “no result”. Using a field with type java.util.Optional is also problematic if the class needs to be Serializable, which java.util.Optional is not

    使用任何像 Optional 的类型作为字段或方法参数都是不可取的. Optional 只设计为类库方法的, 可明确表示可能无值情况下的返回类型. Optional 类型不可被序列化, 用作字段类型会出问题的

    借鉴

    相关文章

      网友评论

          本文标题:JDK8新特性之:Optional

          本文链接:https://www.haomeiwen.com/subject/rovwbftx.html