V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
• 请不要在回答技术问题时复制粘贴 AI 生成的内容
ignore
V2EX  ›  程序员

看完这块代码,我久久不能平静

  •  4
     
  •   ignore · 2021-04-08 16:26:31 +08:00 · 12026 次点击
    这是一个创建于 1358 天前的主题,其中的信息可能已经有所发展或是发生改变。

    try { .... if(url == null) { throw new NullPointerException(); } .... } catch (IOException e) { e.fillInStackTrace(); }

    64 条回复    2021-04-09 16:33:25 +08:00
    TmacV2
        1
    TmacV2  
       2021-04-08 16:29:53 +08:00 via iPhone
    为啥
    iRiven
        2
    iRiven  
       2021-04-08 16:31:42 +08:00
    @TmacV2 url 为空的时候直接调用就会抛出 NullPointerException
    ignore
        3
    ignore  
    OP
       2021-04-08 16:34:14 +08:00
    真没想到能遇上这样的代码,以前看着别人的截图也就乐乐
    xuanbg
        4
    xuanbg  
       2021-04-08 16:44:45 +08:00
    这个 catch 是为可能是不合法的或者无法访问的 url 准备的
    misaka19000
        5
    misaka19000  
       2021-04-08 16:45:28 +08:00
    可能是为了方便在 catch 中处理空指针异常
    w4w
        6
    w4w  
       2021-04-08 16:51:10 +08:00
    遇到 NullPointerException,严禁使用 catch 来隐藏编码错误
    LGA1150
        7
    LGA1150  
       2021-04-08 17:00:42 +08:00   ❤️ 1
    @w4w #6
    catch 的是 IOException
    pkupyx
        8
    pkupyx  
       2021-04-08 17:01:56 +08:00
    @xuanbg 这个 catch 应该是管网络 IO 不可用的异常
    phpfpm
        9
    phpfpm  
       2021-04-08 17:03:06 +08:00   ❤️ 9
    看完这个帖子,我久久不能平静
    LGA1150
        10
    LGA1150  
       2021-04-08 17:05:46 +08:00   ❤️ 3
    @ignore 能把完整代码贴出来么?显式抛 NPE 很可能是为了快速失败( fail-fast )
    https://stackoverflow.com/questions/45632920/why-should-one-use-objects-requirenonnull/45632988
    ychost
        11
    ychost  
       2021-04-08 17:09:32 +08:00   ❤️ 1
    可能完全是为了终止当前语句块,但是又不想终止方法,可以用下面的骚操作实现:
    do {
    if (url == null) {
    break;
    }

    } while (false)
    unicloud
        12
    unicloud  
       2021-04-08 17:47:16 +08:00
    距离发帖过去 1 小时 20 分钟了,现在心情平静了吗?
    meteor957
        13
    meteor957  
       2021-04-08 17:48:44 +08:00
    现在平静了吗
    altchen
        14
    altchen  
       2021-04-08 17:51:31 +08:00
    现在平静了吗
    楼主你这么容易激动,对不起你这个 ID 啊。:doge
    tabris17
        15
    tabris17  
       2021-04-08 17:51:39 +08:00   ❤️ 4
    背后的原因让人暖心
    xuanbg
        16
    xuanbg  
       2021-04-08 17:51:46 +08:00
    @pkupyx 对的,url 不为空不代表 url 就正确返回结果,请求出现异常是最正常不过的事情。这时候抛出异常显然不合适,所以要用 try/catch 吃下来 IOException,并通过日志输出异常。
    yeqizhang
        17
    yeqizhang  
       2021-04-08 17:52:41 +08:00
    @LGA1150 #7 赞同这位老哥,这个他手动抛空指针了,后面代码不一定会抛... 所以看情况。这代码确实不太好。11 楼那个看起来更舒服点
    ipwx
        18
    ipwx  
       2021-04-08 17:55:55 +08:00
    我觉得这个代码很好啊(前提是出 null 真是异常而不是预期中的错误)。谁知道我一个 null 放后面的库都会干些啥,到时候真有 null 了都不知道怎么调试。
    wolfie
        19
    wolfie  
       2021-04-08 18:01:38 +08:00
    唯一槽点,扔到了 try 里面。没啥大问题。
    guyeu
        20
    guyeu  
       2021-04-08 18:04:35 +08:00
    感觉没啥毛病啊。。入參不合法还不让抛异常了吗
    AoEiuV020
        21
    AoEiuV020  
       2021-04-08 18:07:34 +08:00   ❤️ 1
    没毛病,很可能是等后面自动抛 npe 就晚了,抛异常前已经执行的语句又不能回滚的,
    kincaider
        22
    kincaider  
       2021-04-08 18:12:30 +08:00
    还不平静吗?
    mengkun
        23
    mengkun  
       2021-04-08 18:14:34 +08:00   ❤️ 14
    Kasumi20
        24
    Kasumi20  
       2021-04-08 18:45:54 +08:00
    保护代码在正常条件下执行而已,难道你从来不检查参数的吗
    iseki
        25
    iseki  
       2021-04-08 18:48:04 +08:00 via Android
    我觉得很多时候这是正确的编码方式,Java 里毕竟没有 checkNotNull
    Leviathann
        26
    Leviathann  
       2021-04-08 18:50:52 +08:00 via iPhone   ❤️ 1
    这个就是 guava 的 precondition.checknotnull 吧
    bigbyto
        27
    bigbyto  
       2021-04-08 18:51:14 +08:00 via iPhone
    不是十分的优雅,不过没觉得有太大的问题。
    shm7
        28
    shm7  
       2021-04-08 19:28:13 +08:00 via iPhone
    不晓得🤷‍♂️ 也许是为了把这种业务错误在这个代码块捕捉完也说不定
    TheWidowMaker
        29
    TheWidowMaker  
       2021-04-08 19:38:44 +08:00 via Android
    @guyeu 抛 npe 就很奇怪了吧?
    raaaaaar
        30
    raaaaaar  
       2021-04-08 19:52:21 +08:00
    @mengkun #23 emmmm
    Jaeden
        31
    Jaeden  
       2021-04-08 19:55:26 +08:00
    throw NullPointerException,catch IOException
    LGA1150
        32
    LGA1150  
       2021-04-08 20:08:34 +08:00   ❤️ 2
    @iseki #25
    Objects.requireNonNull
    iseki
        33
    iseki  
       2021-04-08 20:13:33 +08:00
    @LGA1150 thx
    Blessing1
        34
    Blessing1  
       2021-04-08 20:17:17 +08:00
    平常心对待!!!
    Still4
        35
    Still4  
       2021-04-08 20:23:15 +08:00
    代码不全,估摸着 url 来自于其他地方,抛出错误是合理的,抛出 NPE 不合理
    gamexg
        36
    gamexg  
       2021-04-08 20:36:22 +08:00
    非 java 开发
    如果函数参数不允许 null,那么我会在函数开头直接检查
    如果为参数 null,立刻报错并结束函数,防止程序执行一半后碰到空指针错误还要回滚操作。
    另外代码也能够清晰的表明,函数不允许 null 参数。

    不过一般是返回自定义错误,而不是返回 空指针异常
    hhjswf
        37
    hhjswf  
       2021-04-08 22:25:19 +08:00
    俺寻思着,NPE 还用你抛啊
    cgb1021
        38
    cgb1021  
       2021-04-08 22:50:24 +08:00
    是为了把所有错误都放在 catch 里处理
    wutiantong
        39
    wutiantong  
       2021-04-08 22:58:45 +08:00
    搞不懂你们写 java 的点呢[狗头]
    sutra
        40
    sutra  
       2021-04-09 08:42:27 +08:00
    打开 V2EX 我久久不能平静。
    angryfish
        41
    angryfish  
       2021-04-09 08:47:03 +08:00 via iPhone
    看完代码,我也久久不能平静,写代码怎么了
    szq8014
        42
    szq8014  
       2021-04-09 09:01:26 +08:00
    哈哈,楼主,现在轮到我们久久不能平静了
    CantSee
        43
    CantSee  
       2021-04-09 09:11:44 +08:00
    实习生写的吧
    shutan
        44
    shutan  
       2021-04-09 09:16:44 +08:00
    V 友交流之后应该就平静下来了
    shuqin2333
        45
    shuqin2333  
       2021-04-09 09:22:31 +08:00
    没啥毛病啊
    uselessVisitor
        46
    uselessVisitor  
       2021-04-09 09:39:22 +08:00
    没有前面的代码,不知道 try 是为了干什么
    unco020511
        47
    unco020511  
       2021-04-09 09:40:17 +08:00
    非要解释的话也能解释的通,就是能快速把 npe 抛出来,不然还要到真正使用 url 的时候才能抛出 npe,然后 catch ioExcption 这个也没问题,因为 url != null,不代表就不会出现 io 问题
    passerbytiny
        48
    passerbytiny  
       2021-04-09 09:53:23 +08:00 via Android
    passerbytiny
        49
    passerbytiny  
       2021-04-09 09:54:11 +08:00 via Android
    手机操作容易误操作,蛋疼的很,等我再组织回复
    passerbytiny
        50
    passerbytiny  
       2021-04-09 10:07:24 +08:00 via Android
    第一,不含任何信息的 NullPointerException,就算是方法开头的参数检验,看起来也是怪怪的,你哪怕弄个 NullPointException("参数:参数名") 也比这强;或者说,裸参数构造的 NullPointerException 包含的信息量太少,要是未预期的由 JVM 抛出还行,要是主动去抛出就显得很不负责任。

    第二,< try { .... } catch (IOException e) { e.fillInStackTrace(); >,这是明显的吃掉异常的行为,非常新手或者不负责任的行为。
    sdlzqjf
        51
    sdlzqjf  
       2021-04-09 10:15:00 +08:00
    我不明白楼主为啥不能平静,不知道槽点在哪?从写法上来说这段代码值得商榷,但是从执行上来说是没问题的
    NullPointerException 是运行时异常,IOException 非运行时异常,catch IOException 并不会捕捉到 NullPointerException,仍然会抛给上层,执行起来逻辑是没问题的。
    当然,楼主这段代码没有业务逻辑,所以无法判断 throw NullPointerException 是不是合理
    guyeu
        52
    guyeu  
       2021-04-09 10:15:31 +08:00
    @TheWidowMaker #29 java 自带的 Objects.requireNonNull,Guava 的 Preconditions.chechNotNull 都是抛出空指针异常,这俩 API 的设计者都觉得指针是空的抛个空指针就可以,有什么问题呢?
    lachesis
        54
    lachesis  
       2021-04-09 10:40:38 +08:00
    脱离业务上下文单独看,槽点有,但还没到夸张的地步,能用
    gowk
        55
    gowk  
       2021-04-09 10:47:44 +08:00
    @mengkun 你这个图可笑死我了
    Anarchy
        56
    Anarchy  
       2021-04-09 10:50:55 +08:00 via Android
    槽点在哪?空指针问题提前抛出来没啥问题啊。
    hodur
        57
    hodur  
       2021-04-09 10:53:04 +08:00
    不那么好,但又比用到 url 时自动抛出好一点
    SWYou
        58
    SWYou  
       2021-04-09 12:04:38 +08:00 via iPhone
    看了这个帖子以后,我今天也试了试主动抛出 NPE,感觉可有逼格了。
    crclz
        59
    crclz  
       2021-04-09 12:21:54 +08:00
    必须在函数开头检查引用是否为 null,这是最基础的编程常识。这样就可以区分是调用者出了问题,传入了 null,还是函数体有 bug,在中途访问了 null 。bug 就被局限在小范围内,而不是跨函数找 bug 。

    除此之外,没有代码上下文,唯一可能出问题的就是把 IOException 掩盖掉的问题。


    @guyeu C# visual studio 对传入参数的代码建议也包含 if(x == null) throw new NullReferenceException(nameof(x)),和 java 的思想一致。
    nowto
        60
    nowto  
       2021-04-09 13:13:03 +08:00 via Android
    错误要早发现早暴露,能在编译器暴露的,就不要等到运行期。就算运行期也要能早暴露尽早暴露。所以一般会在 public 函数开始处做参数校验,抛出业务相关异常;而且应该尽量在 javadoc 注明某参数不接受 null,会抛什么样的异常。

    如果不做显式校验,而是使用到这个参数时依靠 jvm 自动报错:
    1 、会晚; 2 、是一个业务无关的异常; 3 、随着重构的进行,入参和参数使用的位置可能会很远,甚至不在同一个方法
    justforlook44444
        61
    justforlook44444  
       2021-04-09 14:25:36 +08:00
    姑且不谈 try catch,
    github 上搜索 throw new NullPointerException,代码有 500 万行,其中很多都是这种写法;
    jdk 里面也有这种写法
    jdk/src/java.xml.crypto/share/classes/javax/xml/crypto/dsig/dom/DOMSignContext.java
    public DOMSignContext(Key signingKey, Node parent) {
    if (signingKey == null) {
    throw new NullPointerException("signingKey cannot be null");
    }
    if (parent == null) {
    throw new NullPointerException("parent cannot be null");
    }
    setKeySelector(KeySelector.singletonKeySelector(signingKey));
    this.parent = parent;
    }
    所以你不能平静的点在哪里?
    DavidDee
        62
    DavidDee  
       2021-04-09 15:52:05 +08:00
    fail early?
    chinvo
        63
    chinvo  
       2021-04-09 15:56:02 +08:00 via iPhone
    检查参数不应该是在方法开头

    if (url == null) throw new ArgumentNullException(nameof(url));

    privatetan
        64
    privatetan  
       2021-04-09 16:33:25 +08:00
    很多源码不都有这样的判断么
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   1161 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 29ms · UTC 18:30 · PVG 02:30 · LAX 10:30 · JFK 13:30
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.