<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                ??一站式輕松地調用各大LLM模型接口,支持GPT4、智譜、豆包、星火、月之暗面及文生圖、文生視頻 廣告
                ## Chapter 10. Exceptions(異常) ### Item 69: Use exceptions only for exceptional conditions(僅在確有異常條件下使用異常) Someday, if you are unlucky, you may stumble across a piece of code that looks something like this: 你可能會偶然發現這樣一段代碼: ``` // Horrible abuse of exceptions. Don't ever do this! try { int i = 0; while(true) range[i++].climb(); } catch (ArrayIndexOutOfBoundsException e) { } ``` What does this code do? It’s not at all obvious from inspection, and that’s reason enough not to use it (Item 67). It turns out to be a horribly ill-conceived idiom for looping through the elements of an array. The infinite loop terminates by throwing, catching, and ignoring an ArrayIndexOutOfBoundsException when it attempts to access the first array element outside the bounds of the array. It’s supposed to be equivalent to the standard idiom for looping through an array, which is instantly recognizable to any Java programmer: 這段代碼是做什么的?從表面上看,一點也不明顯,這足以成為不使用它的充分理由([Item-67](/Chapter-9/Chapter-9-Item-67-Optimize-judiciously.md))。事實證明,這是一個用于遍歷數組的元素的非常糟糕的習慣用法。當試圖訪問數組邊界之外的數組元素時,通過拋出、捕獲和忽略 ArrayIndexOutOfBoundsException 來終止無限循環。如下循環遍歷數組的標準習慣用法,任何 Java 程序員都可以立即識別它: ``` for (Mountain m : range) m.climb(); ``` So why would anyone use the exception-based loop in preference to the tried and true? It’s a misguided attempt to improve performance based on the faulty reasoning that, since the VM checks the bounds of all array accesses, the normal loop termination test—hidden by the compiler but still present in the for-each loop—is redundant and should be avoided. There are three things wrong with this reasoning: 那么,為什么會有人使用基于異常的循環而不使用習慣的循環模式呢?由于 VM 檢查所有數組訪問的邊界,所以誤認為正常的循環終止測試被編譯器隱藏了,但在 for-each 循環中仍然可見,這無疑是多余的,應該避免,因此利用錯誤判斷機制來提高性能是錯誤的。這種思路有三點誤區: - Because exceptions are designed for exceptional circumstances, there is little incentive for JVM implementors to make them as fast as explicit tests. 因為異常是為特殊情況設計的,所以 JVM 實現幾乎不會讓它們像顯式測試一樣快。 - Placing code inside a try-catch block inhibits certain optimizations that JVM implementations might otherwise perform. 將代碼放在 try-catch 塊中會抑制 JVM 可能執行的某些優化。 - The standard idiom for looping through an array doesn’t necessarily result in redundant checks. Many JVM implementations optimize them away. 遍歷數組的標準習慣用法不一定會導致冗余檢查。許多 JVM 實現對它們進行了優化。 In fact, the exception-based idiom is far slower than the standard one. On my machine, the exception-based idiom is about twice as slow as the standard one for arrays of one hundred elements. 事實上,基于異常的用法比標準用法慢得多。在我的機器上,用 100 個元素的數組測試,基于異常的用法與標準用法相比速度大約慢了兩倍。 Not only does the exception-based loop obfuscate the purpose of the code and reduce its performance, but it’s not guaranteed to work. If there is a bug in the loop, the use of exceptions for flow control can mask the bug, greatly complicating the debugging process. Suppose the computation in the body of the loop invokes a method that performs an out-of-bounds access to some unrelated array. If a reasonable loop idiom were used, the bug would generate an uncaught exception, resulting in immediate thread termination with a full stack trace. If the misguided exception-based loop were used, the bug-related exception would be caught and misinterpreted as a normal loop termination. 基于異常的循環不僅混淆了代碼的目的,降低了代碼的性能,而且不能保證它能正常工作。如果循環中存在 bug,使用異常進行流程控制會掩蓋該 bug,從而大大增加調試過程的復雜性。假設循環體中的計算步驟調用一個方法,該方法對一些不相關的數組執行越界訪問。如果使用合理的循環習慣用法,該 bug 將生成一個未捕獲的異常,導致線程立即終止,并帶有完整的堆棧跟蹤。相反,如果使用了基于異常的循環,當捕獲與 bug 相關的異常時,會將其誤判為正常的循環終止條件。 The moral of this story is simple: **Exceptions are, as their name implies, to be used only for exceptional conditions; they should never be used for ordinary control flow.** More generally, use standard, easily recognizable idioms in preference to overly clever techniques that purport to offer better performance. Even if the performance advantage is real, it may not remain in the face of steadily improving platform implementations. The subtle bugs and maintenance headaches that come from overly clever techniques, however, are sure to remain. 這個案例的寓意很簡單:**顧名思義,異常只適用于確有異常的情況;它們不應該用于一般的控制流程。** 更進一步說,使用標準的、易于識別的習慣用法,而不是聲稱能夠提供更好性能的過于抖機靈的技術。即使性能優勢是真實存在的,但在穩步改進平臺實現的前提下,這種優勢也并不可靠。而且,來自抖機靈的技術存在的細微缺陷和維護問題肯定會繼續存在。 This principle also has implications for API design. **A well-designed API must not force its clients to use exceptions for ordinary control flow.** A class with a “state-dependent” method that can be invoked only under certain unpredictable conditions should generally have a separate “state-testing” method indicating whether it is appropriate to invoke the state-dependent method. For example, the Iterator interface has the state-dependent method next and the corresponding state-testing method hasNext. This enables the standard idiom for iterating over a collection with a traditional for loop (as well as the for-each loop, where the hasNext method is used internally): 這個原則對 API 設計也有影響。一個設計良好的 API 不能迫使其客戶端為一般的控制流程使用異常。只有在某些不可預知的條件下才能調用具有「狀態依賴」方法的類,通常應該有一個單獨的「狀態測試」方法,表明是否適合調用「狀態依賴」方法。例如,Iterator 接口具有「狀態依賴」的 next 方法和對應的「狀態測試」方法 hasNext。這使得傳統 for 循環(在 for-each 循環內部也使用了 hasNext 方法)在集合上進行迭代成為標準習慣用法: ``` for (Iterator<Foo> i = collection.iterator(); i.hasNext(); ) { Foo foo = i.next(); ... } ``` If Iterator lacked the hasNext method, clients would be forced to do this instead: 如果 Iterator 缺少 hasNext 方法,客戶端將被迫這樣做: ``` // Do not use this hideous code for iteration over a collection! try { Iterator<Foo> i = collection.iterator(); while(true) { Foo foo = i.next(); ... } } catch (NoSuchElementException e) { } ``` This should look very familiar after the array iteration example that began this item. In addition to being wordy and misleading, the exception-based loop is likely to perform poorly and can mask bugs in unrelated parts of the system. 這與一開始舉例的對數組進行迭代的例子非常相似,除了冗長和誤導之外,基于異常的循環執行效果可能很差,并且會掩蓋系統中不相關部分的 bug。 An alternative to providing a separate state-testing method is to have the statedependent method return an empty optional (Item 55) or a distinguished value such as null if it cannot perform the desired computation. 提供單獨的「狀態測試」方法的另一種方式,就是讓「狀態依賴」方法返回一個空的 Optional 對象([Item-55](/Chapter-8/Chapter-8-Item-55-Return-optionals-judiciously.md)),或者在它不能執行所需的計算時返回一個可識別的值,比如 null。 Here are some guidelines to help you choose between a state-testing method and an optional or distinguished return value. If an object is to be accessed concurrently without external synchronization or is subject to externally induced state transitions, you must use an optional or distinguished return value, as the object’s state could change in the interval between the invocation of a state-testing method and its state-dependent method. Performance concerns may dictate that an optional or distinguished return value be used if a separate statetesting method would duplicate the work of the state-dependent method. All other things being equal, a state-testing method is mildly preferable to a distinguished return value. It offers slightly better readability, and incorrect use may be easier to detect: if you forget to call a state-testing method, the statedependent method will throw an exception, making the bug obvious; if you forget to check for a distinguished return value, the bug may be subtle. This is not an issue for optional return values. 有一些指導原則,幫助你在「狀態測試」方法、Optional、可識別的返回值之間進行選擇。(1)如果要在沒有外部同步的情況下并發地訪問對象,或者受制于外部條件的狀態轉換,則必須使用 Optional 或可識別的返回值,因為對象的狀態可能在調用「狀態測試」方法與「狀態依賴」方法的間隔中發生變化。(2)如果一個單獨的「狀態測試」方法重復「狀態依賴」方法的工作,從性能問題考慮,可能要求使用 Optional 或可識別的返回值。(3)在所有其他條件相同的情況下,「狀態測試」方法略優于可識別的返回值。它提供了較好的可讀性,而且不正確的使用可能更容易被檢測:如果你忘記調用「狀態測試」方法,「狀態依賴」方法將拋出異常,使錯誤顯而易見;(4)如果你忘記檢查一個可識別的返回值,那么這個 bug 可能很難發現。但是這對于返回 Optional 對象的方式來說不是問題。 In summary, exceptions are designed for exceptional conditions. Don’t use them for ordinary control flow, and don’t write APIs that force others to do so. 總之,異常是為確有異常的情況設計的。不要將它們用于一般的控制流程,也不要編寫強制其他人這樣做的 API。 --- **[Back to contents of the chapter(返回章節目錄)](/Chapter-10/Chapter-10-Introduction.md)** - **Next Item(下一條目):[Item 70: Use checked exceptions for recoverable conditions and runtime exceptions for programming errors(對可恢復情況使用 checked 異常,對編程錯誤使用運行時異常)](/Chapter-10/Chapter-10-Item-70-Use-checked-exceptions-for-recoverable-conditions-and-runtime-exceptions-for-programming-errors.md)**
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看