簡體   English   中英

Java:為什么我不能在Comparator中拋出異常?

[英]Java: why can't I throw an exception in Comparator?

直接的答案是因為Comparator.compare的接口被指定為不會拋出異常。 但那是為什么呢?

或者說它不同:我的Comparator必須依賴於可以拋出異常的函數。 從理論上講,這不應該發生。 但如果它發生了,我希望它突破我使用Comparator (在Collections.sort )的整個函數。 即我希望它只是表現為發生了未處理的異常。

看起來這是不可能以一種明顯的自然方式(因為如果接口說它不能拋出異常,它就不能)。

我該如何解決這個問題? 有一個丑陋的嘗試/捕獲並打印出異常並希望我認識到它? 這似乎是一種非常丑陋的方式。

您始終可以拋出RuntimeException或從中派生的RuntimeException ,甚至可以從未明確聲明自己拋出異常的方法中拋出。

在這種情況下,我會重新拋出AssertionError因為您認為無法引發異常。 不要忘記使用initCause()方法傳播信息( AssertionError沒有構造函數接受Throwable

這是Comparator.compare方法的合同。 如果你想使用它,你應該遵循規則不要從它拋出已檢查的異常:)同時,你可以拋出未經檢查的異常( RuntimeException或其子類),這不會破壞合同。

這是因為你沒有用Lombok的@SneakyThrows注釋注釋你的方法。
請訪問http://projectlombok.org/features/SneakyThrows.html查看

龍目島主頁上的演示和幻燈片也值得一看http://projectlombok.org/

您在問題標題和問題正文中提出了不同的問題。

您不清楚為什么compare()方法使用的異常函數會拋出異常。 這可能是因為集合中存在某些無法比較的對象(如NaN數字值),或者是因為某些對象無法相互比較。

為什么我不能在比較器中拋出異常?

我猜Comparator.compare()不是為了拋出一個已檢查的異常,因為:

  1. 假設您希望比較/排序的任何項目始終具有可比性。

  2. 如果Comparator.compare()可以拋出某種預期的(即已檢查的)異常,那么我可以設想一些不受歡迎的情況:

    一種。 排序可以中止,因為那里存在某種不可比較的對象 - 可能的反應是刪除不可比較的對象並再次嘗試排序

    對同一對象集合的不同排序的多種排序有時會中止異常,有時會取決於是否在排序期間出現了一對無法比較的對象進行比較

這當然只是我猜想的。

我該如何解決這個問題?

我將假設Comparator.compare()使用的異常可能函數拋出異常的原因是因為集合中存在一個無法Comparator.compare()的對象(如NaN數字值)。 選項包括:

  1. 在刪除了無法比較的對象的情況下對列表的副本進行排序。

  2. 拋出未檢查(運行時)異常以中止排序。 不確定除了上面的#1之外你會做什么。

  3. 按照NaN方法進行操作,使這些對象在開始或結束時出現。

    NaN值通常與其他值無法比較,但在排序期間,比較器定義其自己的總排序,以便NaN值最終在排序集合的末尾。

    http://download.oracle.com/javase/1.4.2/docs/api/java/util/Arrays.html#sort(雙[])

    ... <relation不提供所有浮點值的總順序; ... NaN值既不比任何浮點值都大,也不等於任何浮點值,甚至本身。

    ...要允許排序繼續,...此方法使用Double.compareTo(java.lang.Double)強加的總順序。

    ...此排序與<relation的不同之處在於...... NaN被認為大於任何其他浮點值。 出於排序的目的,所有NaN值被認為是等效的並且相等。

    為此,請對Comparator.compare()編碼,使得任何無法比較的對象始終比任何可比對象都要大,並且它總是與任何其他無法比較的對象進行比較。

有兩種方法可以解決這個問題:

  1. 捕獲異常並將其拋入java.lang.RuntimeException()
  2. 捕獲異常並使用Log4J或SLF4J(或您認為合適的任何記錄器工廠)記錄異常。

比較器比較方法的合同不會引發異常。

您可以通過使用許多技巧重新拋出已檢查的異常並避免編譯錯誤。 最簡單的是;

try {
   // something
} catch (Exception e) {
   Thread.currentThread().stop(e);
}

但是,由於編譯器不知道你已經這樣做了。 如果你不小心,你可以把它和自己混淆。 閉包的目標之一是正確處理比較器之類的檢查異常(而其他人則希望它們消失)

本文描述了為什么從Comparator接口內部拋出RuntimeException是一個壞主意,它顯示了兩種良好實踐方法的示例源代碼,以便從不支持它們的接口中處理已檢查的異常:1)將問題分成兩部分件,或2)使用您自己的比較器,支持檢查異常。

https://www.ibm.com/developerworks/library/j-ce/index.html

Comparator接口定義了一個契約。 該合同不允許此方法拋出運行時異常(除非違反通用類型安全性,否則稱為調用代碼中的錯誤)。 使用此比較器的方法合法地依賴它來比較兩個文件,而不會拋出任何異常。 他們不會准備處理從compare()意外冒泡的異常。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM