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

try catch 和 if 在处理程序可能的出错上有什么区别?

  •  1
     
  •   aoscici2000 · 2019-06-24 15:04:13 +08:00 · 4149 次点击
    这是一个创建于 2015 天前的主题,其中的信息可能已经有所发展或是发生改变。

    比如说抽取文章前 100 字作为简介, 两种方法有什么区别

    
    String content = ".........."
    
    try {
        content = content.substring(0, 100)
    } catch (StringIndexOutOfBoundsException e) {
        // pass
    }
    
    if ( content.length() > 100 ) {
        content = content.substring(0, 100)
    }
    
    
    26 条回复    2019-07-23 08:10:35 +08:00
    a719114136
        1
    a719114136  
       2019-06-24 15:06:18 +08:00 via Android
    区别就是一个 try catch 和一堆 if。
    当然 java 的特性,很多时候你必须 try catch
    xiaopang132
        2
    xiaopang132  
       2019-06-24 15:24:58 +08:00
    如果程序出现了 catch 中的异常,程序会继续往下跑,但是如果 if 中出现了异常,程序会停止.
    linxb
        3
    linxb  
       2019-06-24 15:34:25 +08:00
    try catch 可以处理一些程序中断的异常
    questionlin
        4
    questionlin  
       2019-06-24 15:35:27 +08:00   ❤️ 1
    try...catch 的设计是,一个程序只有一个,一般在最外层,统一处理所有错误
    chendy
        5
    chendy  
       2019-06-24 15:37:45 +08:00
    区别是第二种更已读,性能也更好
    除非必要否则不要用捕获异常的方式做业务
    msg7086
        6
    msg7086  
       2019-06-24 15:38:30 +08:00
    异常一般用在程序员假定本应正常工作的情况; if 一般用在程序员假定本来就可能会触发的情况。
    比如,如果 content 是用户输入,那么用户输入多少字都有可能,所以用 if。
    如果 content 是某个专门输出大量文章的函数输出的产物,正常情况下都应该输出超过 100 字内容的,如果少于 100 字那就是程序工作不正常了,这种时候就可以用异常。

    异常说白了也是 if 触发的。substring 里有 if (length <= 100) throw StringIndexOutOfBoundsException。
    q8164305
        7
    q8164305  
       2019-06-24 15:40:59 +08:00 via Android
    异常一般只用在程序员不能控制的地方,如能控制,尽量不用异常
    geelaw
        8
    geelaw  
       2019-06-24 15:44:19 +08:00   ❤️ 2
    @a719114136 #1
    @questionlin #4
    这个想法非常危险,如果不细致地处理异常,外面的处理器通常不能明白到底发生了什么,如果这时继续运行将会带来不可预料的结果。

    @msg7086 #6
    不全是,比如所有的网络访问都应该被假定可以失败,但是很多高级语言中只能通过 try...catch 来捕获异常(因为错误代码已经被转换为异常)。

    ——————

    回到题主提到的问题,第二种写法效率更好。
    palmers
        9
    palmers  
       2019-06-24 15:46:25 +08:00   ❤️ 1
    1. 在 java 中, 异常栈是有成本的, 在这段代码里, 很明显的 if 判断的成本远远大于异常栈的成本;
    2. 在程序设计上, 能够提前预知的异常都不应该依赖 catch 去帮你捕获;很多 java 程序设计的书籍也有提到不应该利用异常栈做流程处理, 在这里也是类似的道理;
    3. 使用 try...catch 一般都是为了容错,而不是为了用来做类似判断的逻辑处理;
    palmers
        10
    palmers  
       2019-06-24 15:47:27 +08:00
    @palmers 对不起 第一条写反了 反正大概意思你明白就行
    zqx
        11
    zqx  
       2019-06-24 15:50:04 +08:00 via Android
    正常的语言里,try 都是用于捕获未知的错误,如果你都知道这个表达式在某些条件下一定会抛出错误,那就应该用判断条件说明它
    kzfile
        12
    kzfile  
       2019-06-24 15:54:40 +08:00
    错误天然可以传递
    使用 if 你一般要在发生错误的上一层处理错误.
    但使用错误传递,你可以有更多的选择
    lithiumii
        13
    lithiumii  
       2019-06-24 16:19:55 +08:00
    java 不懂,反正 py 是偏好 EAFP ( Easier to ask for forgiveness than permission,字面意思:请求原谅比请求许可更容易)多于 LBYL ( Look before you leap,字面意思:跳之前先看清楚),然后 EAFP 的用法一般就是 try 后面再 catch 已知的特定错误(反正你没事儿别一口气 catch 所有的错误就是了)。
    NoKey
        14
    NoKey  
       2019-06-24 16:27:26 +08:00
    if 能判断的,你用 try 去搞,你这个写法,我还是第一次见啊。。。
    niubee1
        15
    niubee1  
       2019-06-24 16:34:50 +08:00
    一般的语言,只能 return 一个值, 而错误包含了 3 个信息,1 是是不是错了 2 是是啥错 3 是出错的地方提供了啥信息。 你说一个强类型的语言要怎么优雅的弥合这个鸿沟?而异常机制是另开通道来把正常逻辑和错误处理逻辑解耦开的方式, 保证了正常的业务逻辑不受到错误的影响。 而基于返回值的方式处理错误,是等于把处理错误作为了业务逻辑必须关心的话题了, 这样简单直接, 但是面对复杂的容易出错的部分耦合在一起的逻辑就会显得很杂乱,因为内部正常逻辑和错误处理逻辑是交织在一起的。
    rizon
        16
    rizon  
       2019-06-24 16:43:29 +08:00
    真较真这个也没啥意思,从结果上看似乎一样,但是每个语句都有自己的使命,就算其他语句能达到这个效果,但毕竟不是为此而生的。
    你要真说 try 代替 if 这种非主流做法有什么坏处,也是有很多的。
    catch 的 oob 异常你怎么知道是 endIndex 超出了,还是 beginIndex 超出了?
    在一些其他的方法里,如果你不判断而是直接运行,看看结果如何,那么有些事情在方法里被执行了,然后才抛出问题,小了说这就是浪费,而对于有副作用的函数那就是直接不对了。
    FrankHB
        17
    FrankHB  
       2019-06-24 18:29:38 +08:00
    Locality 和 exception/error neutrality 都没人提就算了,影响 signature 都不管了(好吧好像有一位提了)? Java、Java ……
    要跨过程传播错误状态,你一个个改返回类型?还是先发明个 longjmp ?(习惯没事人肉糟蹋 throws 的当我没说。)
    当然 LZ 这种立即原地 catch 的玩意儿就是 try 反面教材。
    pkookp8
        18
    pkookp8  
       2019-06-24 18:42:06 +08:00 via Android
    @niubee1 我觉得所有这三个信息都可以归结于返回 0 或非 0 来表示。
    只要有提前约定
    blless
        19
    blless  
       2019-06-24 19:08:26 +08:00 via Android
    就感觉很多人连错误处理都不会 一般业务最上层有 try catch,程序内部基本不用了,尽管抛出异常就是了,最上层处理异常就好。业务超出本机控制代码,一般都要额外 try catch,比如网络,磁盘之类的 IO 请求,需要根据业务处理直接抛出还是重试。按我理解一个应用三层 try catch 就够用了
    annoymous
        20
    annoymous  
       2019-06-24 19:21:33 +08:00
    EAFP 与 LBYL 是两种编程风格 爱用哪个用哪个
    zhangchioulin
        21
    zhangchioulin  
       2019-06-24 19:31:12 +08:00
    LBYL
    Look before you leap. This coding style explicitly tests for pre-conditions before making calls or lookups. This style contrasts with the EAFP approach and is characterized by the presence of many if statements.
    In a multi-threaded environment, the LBYL approach can risk introducing a race condition between “ the looking ” and “ the leaping ”. For example, the code, if key in mapping: return mapping[key] can fail if another thread removes key from mapping after the test, but before the lookup. This issue can be solved with locks or by using the EAFP approach.

    EAFP
    Easier to ask for forgiveness than permission. This common Python coding style assumes the existence of valid keys or attributes and catches exceptions if the assumption proves false. This clean and fast style is characterized by the presence of many try and except statements. The technique contrasts with the LBYL style common to many other languages such as C.

    https://docs.python.org/3/glossary.html#term-eafp
    leishi1313
        22
    leishi1313  
       2019-06-25 01:08:57 +08:00 via Android
    我觉得 EAFP 虽然是种好的风格,但在楼主的例子里不是很适用。EAFP 更多地是用在处理程序外部资源的时候,比如文件,线程,网络等等,这时候用 try..catch 更安全也更普遍。
    另外从 readability (可读性)角度来说,处理字符串 /数组越界之类的,明显 if 的可读性更好。用楼主的例子来说,这个函数的需求是截取文章前 100 字作为简介,天然地就会写成 if article.length() <=100 return article else article.substring(0, 100),简单明了,目的明确,写成 try catch 反而还要绕一个弯想一下什么时候会抛这个异常,然后才能明白程序的意图。
    msg7086
        23
    msg7086  
       2019-06-25 03:45:44 +08:00
    @geelaw 网络访问假定失败这个假定和我说的假定还有些不同。
    比如 TCP 协议是一个相对可靠的协议,那么程序员原本就应该假定这个协议是可靠的。TCP 协议出错(比如丢包过多或者被功夫认证)可以被认为是属于「异常」情况的。
    而像 UDP 这样不可靠的报文协议,报文没有送达可以被认为属于正常情况。
    geelaw
        24
    geelaw  
       2019-06-25 04:07:37 +08:00 via iPhone
    @msg7086 #23 我说的是断网
    zw1one
        25
    zw1one  
       2019-06-25 10:19:46 +08:00 via Android
    catch 用来捕获难以避免的异常,尽量不要用 catch 来处理业务逻辑。有效率问题。
    linuxsteam
        26
    linuxsteam  
       2019-07-23 08:10:35 +08:00 via Android
    @xiaopang132 你这是什么操作?
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   2480 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 24ms · UTC 15:38 · PVG 23:38 · LAX 07:38 · JFK 10:38
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.