Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using Ternary Operator to Throw Checked or Unchecked Exceptions

My original question used FileNotFoundException and IllegalStateException and therefore they are included in the answer. I have changed them to their superclasses IOException and RuntimeException respectively for simplicity.


This compiles (not using ternary, 1 checked, 1 unchecked):

private void test() throws IOException { // throws is required
    if (new Random().nextInt(2)==0) throw new IOException();
    throw new RuntimeException();
}

This also compiles (using ternary, 2 unchecked exceptions):

private void test3() { // throws not required
    throw new Random().nextInt(2)==0 ? new UncheckedIOException(null) : new RuntimeException();
}

But why does this not compile (using ternary, 1 checked, 1 unchecked)?

private void test2() throws IOException {
    throw new Random().nextInt(2)==0 ? new IOException() : new RuntimeException();
}

From Eclipse:

Unhandled exception type Exception

2 quick fixes available:

J! Add throws declaration

J! Surround with try/catch


Another pair of examples

This compiles:

private void test4() { // throws not required
    if (new Random().nextInt(2)==0) throw new Error();
    throw new RuntimeException();
}

This does not:

private void test5() {
    throw new Random().nextInt(2)==0 ? new Error() : new RuntimeException();
}

From Eclipse:

Unhandled exception type Throwable

2 quick fixes available:

J! Add throws declaration

J! Surround with try/catch

like image 750
blackr1234 Avatar asked May 01 '19 14:05

blackr1234


Video Answer


1 Answers

Why does this not compile?

Because the inferred type of the conditional ?: operator in this case is Exception, following the rules of JLS 15.25.3. While the JLS gets complicated really quickly, the rules are trying to find "the most specific type where there's an implicit conversion from both of the operand types". A sort of "nearest common ancestor".

The inheritance hierarchy in this case is:

                      Exception
                   /              \
           IOException           RuntimeException
               /                         \
      FileNotFoundException           IllegalStateException

... so the nearest common ancestor is Exception. Your code is somewhat equivalent to:

private void test() throws FileNotFoundException {
    Exception exception = 1==0 ? new FileNotFoundException() : new IllegalStateException();
    throw exception;
}

Hopefully you already understand why that would fail to compile... in which case with any luck it's all clear now :)

like image 66
Jon Skeet Avatar answered Sep 23 '22 07:09

Jon Skeet