javaWeber
V2EX  ›  Java

请教下 java8 的 Optional。。

  •  
  •   javaWeber · Mar 25, 2020 · 5976 views
    This topic created in 2417 days ago, the information mentioned may be changed or developed.

    最近写了一堆空指针,打算改用下 java8 的 Optional 。。

    请问下以下代码,怎么用 Optional 表示。

    1. 判断 A 是否为空,然后修改 B 或者执行其他逻辑。

    想过用 if (isPresent())去判空,又觉得跟之前的 if 没什么区别。。

    String str="123";
    String result="abc";
    if(str!=null){
    	result+="def";
    }
    

    2.判断 A 是否为空,然后根据情况执行 if else 里面的逻辑。。

    java9 有个 ifPresentOrElse(),不过项目里用的是 java8 。

    String str="123";
    String result="abc";
    if(str!=null){
    	result+="def";
    }else {
        result+="ghi";
    }
    
    Supplement 1  ·  Mar 25, 2020
    我这里的例子不太准确,判断的是字符串,应该改成对象的。

    我想避免对象判空,也就是用 Optional 减少 if(对象!=空)这类操作。。
    31 replies  •  2020-08-13 10:06:24 +08:00
    javaWeber
    javaWeber
    OP
    Mar 25, 2020
    1
    3.还有就是 字符串类型的 Optional.orElse(),这里面 orElse 的默认值用什么好?

    我看网上很多用.orElse("default"),为空时就给了个默认值"default"或者"unknown"。。感觉很奇怪。
    alphatoad
    alphatoad
    Mar 25, 2020
    2
    用 FP 的思路就很好理解了,相当于 Haskell 的 Maybe
    data Maybe a = Nothing | Just a
    weakish
    weakish
    Mar 25, 2020
    3
    A 是否为空决定是否对 B 进行操作,这里对 B 的操作并没有用到 A 的值,不会碰到空指针,也就没必要用 Optional 。
    weakish
    weakish
    Mar 25, 2020
    4
    "default" 或者 "unknown" 这是教程里为了演示用的吧。实际场景中,就是应该用什么默认值就用什么默认值呀,原来用 `a == null ? a : "xxx"`,现在改成 `a.orElse("xxx")`,只是写法变一下,并不影响默认值的选取。
    bkmi
    bkmi
    Mar 25, 2020 via Android
    5
    要不用 kotlin 吧
    但是你这两个例子,看不出哪 NPE,就你现在的写法最简单了…
    lxychn
    lxychn
    Mar 25, 2020
    6
    不用 optional 的话判断为空的 if 忘了写就可能会出错,用了 optional 的一定要用 ifPresent()去判断,不然 compiler 就会报错,避免忘了检查是否为空的情况

    optional 好像和 lamda 结合用的更多
    xixinimei
    xixinimei
    Mar 25, 2020
    7
    当你意识到一个变量该用 optional 的时候,可以不用 optional 。

    Java 的 Optional 表达能力有限,主要是对自由变量的重新赋值很麻烦,需要用到容器类来包装。
    optional
    optional
    Mar 25, 2020 via iPhone❤️3
    8
    Optional 的精髓在 map ifpresent stream
    noreplay
    noreplay
    Mar 25, 2020 via Android❤️2
    9
    @optional 结合 id 来看,特别让人信服🤓🤓
    chendy
    chendy
    Mar 25, 2020
    10
    Optional 的有点是可以挂回调,配合其他(比如 stream ) api 可以一路点点点点写完一套逻辑,但是如果不习惯挂回调的话就很别扭
    简单场景单独判断 null 足以
    yty2012g
    yty2012g
    Mar 25, 2020
    11
    第一,如你图上的示例,确实使用 Optional 和判断是否等于 null 没有区别,因为你的条件分支里面没有使用 str 这个变量。在此情况下,我认为没有区别。
    第二,假如你的条件分支有使用 str,那就需要对 str 为 null 的情况赋予其他值,此时可以使用 Optional.orElse("default")或者 Optional.orElseGet(()->"default")这样的方式来代替使用 str 。
    第三,还有一种情况是 str 等于 null 我要抛异常,很常见,例如 DB 里面查不到数据我要抛异常,此时可以使用 Optional.orElseThrow(() -> new StrNotFoundException("str 没找到!"))类似的.
    综上,不是什么情况下 Optional 都能达到你想要的效果,不过最差的基本面也是和判断是否为 null 类似,所以可以尝试去使用
    guyeu
    guyeu
    Mar 25, 2020
    12
    @javaWeber #1 如果不知道用什么好,就用 orThrow,抛出异常。
    CommandZi
    CommandZi
    Mar 25, 2020
    13
    你这两个例子,不管 str 是不是 null,都不会空指针吧。
    Aresxue
    Aresxue
    Mar 25, 2020
    14
    optional.ifPresent(修改 B), 但就像上面说的你这个简单调用还不涉及 npe 没必要使用
    cyspy
    cyspy
    Mar 25, 2020
    15
    flatmap
    mezi04
    mezi04
    Mar 25, 2020
    16
    个人理解:把 optional 想想成盒子,of 或者 ofNullable 传入的参数就是盒子里边的东西。optional 的目的是从这个盒子里拿出一个非空数据,你可以通过一系列的方法转换盒子里的数据( fliter/flatMap ),或者告诉盒子,如果为空怎么做( orElse/ifPresent 等)。如果你的模型不符合这个,就没有用 optional 的必要
    hantsy
    hantsy
    Mar 25, 2020
    17
    用 orElseThrow 抛出异常就好了,我也比较常用。
    Optional<Post> post = posts.findById(id)

    post.map(....).orElseThrow(()->new PostNotFoundException(id))
    hantsy
    hantsy
    Mar 25, 2020❤️1
    19
    Optional 本身就是解决这中 If Null 判断,如果又回到 If 来判断,还不如不用。
    javaWeber
    javaWeber
    OP
    Mar 25, 2020
    21
    @CommandZi 你这两个例子,不管 str 是不是 null,都不会空指针吧。
    ==============================================
    我这里的例子写得不太准确,判断的是字符串,应该改成判断对象是否为空的。
    ```
    if(对象!=空){

    }
    ```
    MakHoCheung
    MakHoCheung
    Mar 25, 2020
    22
    Optional 针对的是 str 。
    这代码就算放到 kotlin 也要判 null,因为你的 str 是 String?类型
    XiLemon
    XiLemon
    Mar 25, 2020
    23
    可以参考一下: http://www.yinwang.org/blog-cn/2015/11/21/programming-philosophy 关于 NULL 的处理建议
    ica10888
    ica10888
    Mar 25, 2020
    24
    其实这个是函数式编程的东西,相当于一个包装。不过一般情况下用来处理链式操作,如 getA().getB().getC() 的空指针异常,其实 kotlin 的语法糖要好看一些...
    tachikomachann
    tachikomachann
    Mar 25, 2020
    25
    我的理解是用 Optional 没办法减少判空操作,而是强制你必须判空。所以一旦用了 Optional,就不会无意识地写出 NPE 问题的代码。。
    lyyhello
    lyyhello
    Mar 25, 2020
    26
    你看下 jdk8 用到 Optional 的地方的源码就知道了。如果有明确的返回,不用 Optional,如果因为各种原因(),结果不能保证一定为空,就用 Optional 返回。而且使用者不是简单的判断是否为空,而是和 Stream 紧密联系着用呢
    Jrue0011
    Jrue0011
    Mar 26, 2020
    27
    Optional 要用上 map/flatMap 、filter 。一般应该是一段代码调用多个方法,每个方法入参都是上个方法返回值或返回值部分,Optional 的 map/flatMap 可以避免对每个返回值判断 null,如果对返回值的判断不仅仅是否 null 的话,可以用 filter 判断。

    比如这样。。。

    Optional.of(userId).map(userDao::getPhone).filter(phoneService::isChinaMobile).ifPresent(smsService::sendMsg);
    Optional.of(userId).map(userDao::getPhone).map(phoneBook::getContactListByPhone).orElseGet(Collections::emptyList);
    或者如果有需要抛业务异常,也可以用 orElseThrow
    CommandZi
    CommandZi
    Mar 26, 2020
    28
    @javaWeber Optional 设计是用来减少空指针异常,不是减少 if(对象!=空)这类操作的。你 if 后续代码都没调用对象,说明这只是你程序的固定逻辑而已,不管对象用不用 optional,都是要判断的。
    CommandZi
    CommandZi
    Mar 26, 2020
    29
    @CommandZi 当然这是我使用 Swift 当中的 Optional 的经验,Java 的没有了解。
    MotherShip
    MotherShip
    Apr 1, 2020
    30
    手头上用的比较优雅的玩法大概是,Repository 层返回一个 Optional 对象,为空则直接一路把异常抛到 Controller 层然后统一处理:

    ```java
    String a = Optional.ofNullable("a").orElseThrow(()->{throw new RuntimeException();});
    ```
    至于你这两个例子。。确实用不用没啥区别
    facelezz
    facelezz
    Aug 13, 2020
    31
    楼上回答了那么多,其实 guava 文档里就有解释。
    Besides the increase in readability that comes from giving null a name (增加了可读性,isPresent()比 if xxx!=null 可读性好)
    the biggest advantage of Optional is its idiot-proof-ness.It forces you to actively think about the absent case if you want your program to compile at all, since you have to actively unwrap the Optional and address that case (使用了 option 后,强迫你思考不存在的情况,避免忘记)

    This is especially relevant when you're returning values that may or may not be "present." You (and others) are far more likely to forget that other.method(a, b) could return a null value than you're likely to forget that a could be null when you're implementing other.method. Returning Optional makes it impossible for callers to forget that case, since they have to unwrap the object themselves for their code to compile.

    (对设计的优化,如果你的方法返回值可能存在也可能不存在,就尽量返回 optional,这样别人用你的方法就知道需要判断)
    至于 orElse 这种类型操作,我自己理解的是 4 楼那样,此外,optional 并不是用来简化流程,只是一种设计,让人记住去处理 null
    About   ·   Help   ·   Advertise   ·   Blog   ·   API   ·   FAQ   ·   Privacy   ·   Solana   ·   2390 Online   Highest 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 1341ms · UTC 11:13 · PVG 19:13 · LAX 03:13 · JFK 06:13
    ♥ Do have faith in what you're doing.