JDK8新特性之:Optional

痛点

在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 类型不可被序列化, 用作字段类型会出问题的

借鉴

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 202,802评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,109评论 2 379
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 149,683评论 0 335
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,458评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,452评论 5 364
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,505评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,901评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,550评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,763评论 1 296
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,556评论 2 319
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,629评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,330评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,898评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,897评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,140评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,807评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,339评论 2 342

推荐阅读更多精彩内容

  • Java 8自Java 5(发行于2004)以来最具革命性的版本。Java 8 为Java语言、编译器、类库、开发...
    谁在烽烟彼岸阅读 884评论 0 4
  • 目录结构 介绍 Java语言的新特性2.1 Lambdas表达式与Functional接口2.2 接口的默认与静态...
    夜风月圆阅读 459评论 0 2
  • 前言:Java 8 已经发布很久了,很多报道表明Java 8 是一次重大的版本升级。在Java Code Geek...
    糖宝_阅读 1,321评论 1 1
  • 和我关系很好的一个女孩子,新婚不久,每次跟我聊天,总会跟我抱怨她老公的种种不是,总是跟我抱怨她老公家里人的各种不好...
    沸腾_6d31阅读 561评论 0 0
  • 《死亡诗社》 1.概念 威尔顿预备学院以其沉稳凝重的教学风格和较高的升学率闻名,作为其毕业班的学生,理想就是升入名...
    昔瞳_1404阅读 218评论 2 2