views:

150

answers:

7

The direct answer is because Comparator.compares interface is specified as such that it does not throw exceptions. But why is that?

Or to put it different: My Comparator must depend on a function which can throw an exception. In theory, that should not happen. But if it happens, I want that it breaks out of the whole function where I am using that Comparator (in Collections.sort). I.e. I want that it just behaves as if an unhandled exception has occurred.

It seems that this is not possible in an obvious natural way (because if the interface says that it cannot throw an exception, it can't).

How would I solve this? With an ugly try/catch and print out the exception and hope that I recognize it? That seems to be a quite ugly way.

+9  A: 

You can always throw a RuntimeException, or one derived from it, even from a method not explicitly declaring itself to throw exceptions.

bramp
+3  A: 

This is contract of Comparator.compare method. If you want to use it you should just follow the rule not to throw checked exceptions from it :) Meanwhile, you can throw unchecked exception (RuntimeException or its subclass) and this will not break contract.

Andriy Sholokh
A: 

There are 2 ways of solving this:

  1. Catching the exception and throwing it inside a java.lang.RuntimeException(), or
  2. Catching the exception and logging it using Log4J or SLF4J (or any logger factory you feel comfortable with).

The contract for comparator's compare method doesn't throw exceptions.

The Elite Gentleman
I would advise against logging the error and continue. This is not the kind of error you should ignore.
gawi
I do agree with you, but you're just doing some compare, so in essence, the compare method assume that no exceptions should be thrown. Plus, by logging the exception, you have a stacktrace in file to show you where the exception occurred.
The Elite Gentleman
The logging approach would tell you where the first of your exceptions occured, because it pretty likely that more exceptions will be raised when exceptions are ignored (and yes, logging it and keep working = ignoring).
Willi
The Elite Gentleman
+4  A: 

In this case, I would rethrow an AssertionError since you assume that the exception can't be raised. Don't forget to use the initCause() method to propagate the information (AssertionError doesn't have a constructor accepting a Throwable)

gawi
`AssertionError` has a constructor accepting an `Object`, which will be used as the cause if it's `Throwable`. (Random side note: I believe they're improving this in JDK7.)
ColinD
@ColinD Wow... I've just learned something. thanks.
gawi
+1  A: 

You ask different questions in the question title and in the question body.

You weren't clear on why the exception-capable function used by the compare() method would throw an exception. It's either because there are certain uncomparable objects in the collection (like a NaN numberic value) or else it's because there are certain pairs of objects that can't compared against each other.

Why can't I throw an exception in the Comparator?

I would guess Comparator.compare() isn't designed to throw a checked exception because:

  1. it is assumed that any items that you would wish to compare/sort would always be comparable.

  2. if a Comparator.compare() could throw some sort of expected (i.e. checked) exception, then I can envision a couple of undesirable scenarios:

    a. a sort could abort because there is some sort of uncomparable object in there - the likely response being to remove the uncomparable object(s) and try the sort again

    b. multiple sorts on the different orderings of the same collection of objects could sometimes abort with an exception and sometimes succeed depending on whether or not a pair uncomparable objects happened to come up for comparison during the sort

This is of course just my conjecture.

How would I solve this?

I going to assume that the reason the exception-possible function that your Comparator.compare() uses throws an exception is because there's an uncomparable object in the collection (like a NaN numberic value). Options include:

  1. Sort a copy of the list with the uncomparable object(s) removed.

  2. Throw an unchecked (runtime) exception to abort the sort. Not sure what you would do then other than #1 above.

  3. Follow the NaN approach and make it so those objects come out at beginning or end.

    NaN values are normally uncomparable to other values, but during a sort, the comparator defines its own total ordering so that NaN values end up at the end of the sorted collection.

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

    ... The < relation does not provide a total order on all floating-point values; ... a NaN value compares neither less than, greater than, nor equal to any floating-point value, even itself.

    ... To allow the sort to proceed, ... this method uses the total order imposed by Double.compareTo(java.lang.Double).

    ... This ordering differs from the < relation in that ... NaN is considered greater than any other floating-point value. For the purposes of sorting, all NaN values are considered equivalent and equal.

    To do this, code your Comparator.compare() such that any incomparable object always compares greater than any comparable object and it always compares equal to any other incomparable object.

Bert F
+1  A: 

It's because you haven't annotated your method with Lombok's @SneakyThrows annotation.
Check it out at http://projectlombok.org/features/SneakyThrows.html

The demo and slides on the Lombok homepage are also worth a look http://projectlombok.org/

crowne
A: 

You can rethrow a checked exception and avoid compilation error by using a number of tricks. The simplest is;

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

However, since the compiler has no idea you have done this. You can confuse it and yourself if you are not careful. One of the objectives of closures is to handle checked exceptions in things like Comparators correctly (while others would prefer they went away)

Peter Lawrey