V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
baolinliu442k
V2EX  ›  Java

Java 中的 Optional 应该什么时候用呢,总感觉这样不如直接 if 判断

  •  1
     
  •   baolinliu442k · 245 天前 · 4509 次点击
    这是一个创建于 245 天前的主题,其中的信息可能已经有所发展或是发生改变。

    屏幕截图 2023-08-26 171801.png

    39 条回复    2023-08-27 16:18:00 +08:00
    hello2090
        1
    hello2090  
       245 天前 via iPhone
    你随便 Google 一下就有了哇,你这里更好是用 pData.ifPresent()
    bringyou
        2
    bringyou  
       244 天前   ❤️ 3
    String username = Optional.ofNullable(people).ifPresent(People::getName).orElse(null);
    javapythongo
        3
    javapythongo  
       244 天前
    需要从一个对象连续获取值的时候
    ```
    String username = Optional.ofNullable(people).map(People::getName).orElse(null);
    ```
    bitmin
        4
    bitmin  
       244 天前
    String username = Optional.ofNullable(people).map(People::getName).orElse(null);

    2# ifPresent void
    Leviathann
        5
    Leviathann  
       244 天前
    chaining
    baolinliu442k
        6
    baolinliu442k  
    OP
       244 天前
    @bringyou 太优雅了
    BBCCBB
        7
    BBCCBB  
       244 天前
    链式的时候可以用, 简单判断一个字段是否有值的时候, 真不如 if (xxx != null )
    baolinliu442k
        8
    baolinliu442k  
    OP
       244 天前
    @javapythongo 确实好一点,那大哥,假如 People 对象里面还有一个 Job 对象, 我想获取里面的 jobName, 这种写法可以吗
    baolinliu442k
        9
    baolinliu442k  
    OP
       244 天前
    @BBCCBB 因为我们项目有时候返回几十个字段,以前都是 String name = people == null ? "" : people.getName() 这样
    fkdog
        10
    fkdog  
       244 天前   ❤️ 3
    1. 可以在返回值里使用 optional ,提醒调用方这里返回的值可能为空,包装成 optional 对象就是强制要求调用者对空值情况进行判断处理。
    2. 连续取值。比如你接到一个层级很复杂的 json 对象,将其转换成 map 结构,一层一层的 get 需要判断 null ,用 Optional 的话,就算是内嵌深度是 10 层,也能用一行 optional 解决,避免出现嵌套 10 层 if-else 判断
    baolinliu442k
        11
    baolinliu442k  
    OP
       244 天前
    @Leviathann 链式调用吗
    baolinliu442k
        12
    baolinliu442k  
    OP
       244 天前
    @bitmin 如果 api 这么设计好像也挺清晰的
    baolinliu442k
        13
    baolinliu442k  
    OP
       244 天前
    @fkdog 这两点都还挺有用的,学到了
    baolinliu442k
        14
    baolinliu442k  
    OP
       244 天前
    @hello2090 好哒
    baolinliu442k
        15
    baolinliu442k  
    OP
       244 天前
    @baolinliu442k String jobName = Optional.ofNullable(people).map(People::getJob).map(Job::getJobName).orElse(null);
    这样写也可以,嵌套对象取值还挺方便的
    baolinliu442k
        16
    baolinliu442k  
    OP
       244 天前
    总结一下就是#10 楼大哥说的优势, 感谢大家的回复
    arloor
        17
    arloor  
       244 天前 via Android
    可以减少代码行数,又不损失可读性的时候
    Edward4074
        18
    Edward4074  
       244 天前 via iPhone
    在其他语法丰富的语言里就是
    people?.job?.jobName??””
    在 Java 里就只能是这样了
    hello2090
        19
    hello2090  
       244 天前
    @Edward4074 Groovy!
    cnt2ex
        20
    cnt2ex  
       244 天前
    因为 null 指针的引入本身就是个历史错误。用 Optional 类型改正了这个历史错误。

    虽然在一些情况下,和写检查 null 一样。但是引入了 Optional 类型相当于强制你做检查了。
    yechentide
        21
    yechentide  
       244 天前 via iPhone
    @Edward4074 Swift !
    baolinliu442k
        22
    baolinliu442k  
    OP
       244 天前
    @yechentide dart 里好像也有这个
    Building
        23
    Building  
       244 天前 via iPhone
    惊到我了,以前看到 Java 新增 Optional Value 的时候我还想越来越现代化了,没想到这个老太太的裹脚布果然没让我失望
    fpure
        24
    fpure  
       244 天前
    说实话,没多大用,不如 @NotNull 和 @Nullable
    cyningxu
        25
    cyningxu  
       244 天前
    kotlin:就这?
    caiqichang
        26
    caiqichang  
       244 天前
    kotlin 更优雅
    val jobName = people?.job?.jobName ?: null
    humpy
        27
    humpy  
       244 天前
    基本不用,这就是个 nullability 的残废实现,慢慢等 https://mail.openjdk.org/pipermail/valhalla-spec-experts/2023-May/002276.html
    netabare
        28
    netabare  
       244 天前 via Android   ❤️ 1
    一般是用 orElse 、flatMap 来串接不同的处理过程的吧。
    if isPresent 这个写法太命令式了。直接 get 的话说实话不如不要用 Optional 。
    当然 Optional 确实很难用就是了。
    cheng6563
        29
    cheng6563  
       244 天前   ❤️ 1
    烂设计,没有必要用。
    lisongeee
        30
    lisongeee  
       244 天前   ❤️ 2
    kotlin: val jobName = people?.job?.jobName ?: null
    js/ts: const jobName = people?.job?.jobName?.[0] ?? null
    c#: var jobName = people?.job?.jobName?[0] ?? null
    Swift: let value = obj?.nestedObj?.property
    dart: var jobName = people?.job?.jobName ?: null

    但是肯定有人觉得 Optional 比上面更好用,毕竟祖宗之法不可变
    ikas
        31
    ikas  
       244 天前
    复制一点实际业务代码

    var fileName = file.getName();
    var fileInfo = new FileInfo();
    SessionContext.userName().ifPresent(fileInfo::setUserName);
    MediaTypeFactory.getMediaType(fileName).map(MediaType::toString).ifPresent(fileInfo::setContentType);
    Bingchunmoli
        32
    Bingchunmoli  
       244 天前 via Android
    @lisongeee 有时候??多了有点增加阅读难度,当然也是因为用的不多不够熟悉 kt 。.let 复杂点 ide 提示的自己都看不懂
    tamer
        33
    tamer  
       244 天前
    不是拿来单独取代 if 判断的
    是拿来写 lambda 的
    PTLin
        34
    PTLin  
       244 天前   ❤️ 1
    我还记得以前有人笑过 Optional ,大概是说 Java 的 Maybe 居然有三种状态:Just ,Noting 和 NULL 。
    FrankHB
        35
    FrankHB  
       244 天前   ❤️ 1
    @lisongeee null 就是个阉割版的 Optional ,而且明显更祖宗。
    Optional 本身本来也不是太大的问题(起码回避起来比起无处不在的 null 来说容易多了),问题是 null 这祖宗干不掉,又另外加上 Optional ,本该是同一种目的凭空多出来不同的不兼容的表达方式乃至于扭曲目的本身(不顾历史,强行为现状洗地而寻找不同的用例场合),混起来效果就很感人了。
    FrankHB
        36
    FrankHB  
       244 天前   ❤️ 1
    @PTLin 多几种其实不是直接问题。上古的 cons pair 限制个别元素就能造出 list monad ,用比较现代一点的说法,决定限制的 unit predicate 是 null?;中古一点的 string 同样也是个 monad ,unit pred 是 string-null? 。其实吧,传统数学上 list 和 string 可以就是一回事。那为什么不嫌弃 string 和 list 共存冗余呢?因为 string 好歹有复杂度 hint 表明适合不同场景(激进一点的还有 encoding 甚至 SSO 之类的假设,但把本属于 text 的东西混同 string 有过度设计的问题,这又是另一回事了)。这个意义上 string 是具有更多实现假设的 list 又确实不都能替代 string ,这种不同层次上的冗余适应新的需求,其实不难接受。
    问题是引入的目的和过程。新增的抽象如果没有提供更详细的假设提升到接口的含义,而仅仅是为了给不完善的旧有抽象擦屁股,但被擦屁股的东西又因为兼容性之类的原因没法被彻底替代而只能共存,这样缝合的下场自然不会让用户舒服了。
    为什么说 null 是多余的呢?因为 nullable type 历史上本来就是实现偷懒( null pointer )的结果上反向臆造的抽象。要从需求侧讲,没什么和 Maybe 区分的必要,反倒是传统实现习惯(比如死板的错误处理)导致使用者体验很尴尬。相比之下,C++一样也有 optional<T&>不能随便和 T*等价的历史包袱,这里思想包袱就体现得更明显,因为 nullptr 并没有 Java 一样被迫弄得到处都是的存在感,兼容性问题本该不是借口。
    lisongeee
        37
    lisongeee  
       244 天前
    @FrankHB

    null 我觉得还好,不好的点是没有把 null 做到编译期,实际上可 null 就是一个简单的联合类型

    如果把 null 像 kotlin/ts/c#/Swift/dart 直接做到编译期,我觉得就没啥问题了

    Optional 太长太难用了,还是编译期 null 校验+可选链更好用
    Kaiv2
        38
    Kaiv2  
       244 天前
    补充一个小点: 在 JDK8 时,使用 Optional 总感觉少了个功能, 在一堆链式调用后,
    只有 ifPresent 方法, 不为空的情况下才能执行, 还是需要 if 语句来判断是否为空。
    后面发现 JDK9 添加了一个 ifPresentOrElse 方法来解决这个问题。
    Kaiv2
        39
    Kaiv2  
       244 天前
    @Kaiv2 补充代码

    People p = null; // TODO:
    Optional<People> people = Optional.ofNullable(p);
    Map<String, String> result = new HashMap<>();
    people.map(People::getUsername)
    .ifPresentOrElse(e -> {
    result.put("status", "1");
    result.put("name", e);
    }, () -> {
    result.put("status", "?");
    });

    System.out.println(result);
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   我们的愿景   ·   实用小工具   ·   2884 人在线   最高记录 6543   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 28ms · UTC 09:28 · PVG 17:28 · LAX 02:28 · JFK 05:28
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.