Java:为什么我不能在Comparator中抛出异常?

时间:2010-09-30 16:31:49

标签: java exception exception-handling

直接答案是因为Comparator.compare的接口被指定为不会抛出异常。但那为什么呢?

或者说它不同:我的Comparator必须依赖于可以抛出异常的函数。从理论上讲,这不应该发生。但如果它发生了,我希望它突破我使用ComparatorCollections.sort)的整个函数。即我希望它只是表现为发生了未处理的异常。

似乎这在一种显而易见的自然方式下是不可能的(因为如果界面说它不能抛出异常,它就不能)。

我该如何解决这个问题?有一个丑陋的尝试/捕获并打印出异常并希望我认识到它?这似乎是一种非常丑陋的方式。

8 个答案:

答案 0 :(得分:13)

你总是可以抛出一个RuntimeException,或者从它派生的一个,即使是一个没有明确声明自己抛出异常的方法。

答案 1 :(得分:5)

在这种情况下,我会重新抛出AssertionError,因为您认为无法引发异常。不要忘记使用initCause()方法传播信息(AssertionError没有构造函数接受Throwable

答案 2 :(得分:3)

这是Comparator.compare方法的合同。如果你想使用它,你应该遵循规则,不要从它抛出已检查的例外:) 同时,您可以抛出未经检查的异常(RuntimeException或其子类),这不会破坏合同。

答案 3 :(得分:2)

这是因为您没有使用Lombok的 @SneakyThrows 注释注释您的方法。
请查看http://projectlombok.org/features/SneakyThrows.html

Lombok主页上的演示和幻灯片也值得一看http://projectlombok.org/

答案 4 :(得分:1)

您在问题标题和问题正文中提出了不同的问题。

您不清楚为什么compare()方法使用的具有异常功能会抛出异常。这可能是因为集合中存在某些无法比较的对象(如NaN数字值),或者是因为某些对象无法相互比较。

  

为什么我不能在比较器中抛出异常?

我猜Comparator.compare()不是为了抛出一个已检查的异常,因为:

  1. 假设您希望比较/排序的任何项目总是具有可比性。

  2. 如果Comparator.compare()可以抛出某种预期(即已检查)的异常,那么我可以设想一些不受欢迎的情况:

    一个。排序可以中止,因为那里存在某种不可比较的对象 - 可能的反应是删除不可比较的对象并再次尝试排序

    湾对同一对象集合的不同排序的多种排序有时可以中止异常,有时会取决于在排序期间是否碰巧出现了一对无法比较的对象进行比较

  3. 这当然只是我猜想的。

      

    我该如何解决这个问题?

    我将假设您的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)强加的总顺序。

           

      ......这种排序与<关系... NaN被认为大于任何其他浮点值。出于排序的目的,所有NaN值都被视为等效且相等。

      要做到这一点,请对Comparator.compare()进行编码,使得任何无法比较的对象总是比任何可比对象都要大,并且它总是与任何其他无法比较的对象进行比较。

答案 5 :(得分:0)

有两种方法可以解决这个问题:

  1. 捕获异常并将其放入java.lang.RuntimeException()
  2. 捕获异常并使用Log4J或SLF4J(或您认为合适的任何记录器工厂)记录异常。
  3. 比较器比较方法的合同不会引发异常。

答案 6 :(得分:0)

您可以通过使用许多技巧重新抛出已检查的异常并避免编译错误。最简单的是;

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

但是,由于编译器不知道你已经这样做了。如果你不小心,你可以把它和自己混淆。闭包的目标之一是正确处理比较器之类的检查异常(而其他人则希望它们消失)

答案 7 :(得分:-2)

本文介绍了为什么从Comparator接口内部引发RuntimeException是一个坏主意,并显示了两种良好实践方法的示例源代码,这些方法可以从不支持它们的接口中处理受检查的异常:1)拆分问题分成两部分,或者2)使用支持检查异常的自己的比较器。

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

  

Comparator接口定义合同。该合同不允许该方法抛出运行时异常(除非违反了在调用代码中有错误的通用类型安全性)。使用此比较器的方法合法地依赖于它比较两个文件,而不会引发任何异常。他们将不准备处理来自compare()意外冒泡的异常。