Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Determining compile-time multicatch exception type

I built something I don't really understand - I don't know how it works. I've familiarized myself with this multicatch explaination article.

Consider these two exceptions and code:

public class MyException1 extends Exception {
  // constructors, etc
  String getCustomValue();
}

public class MyException2 extends Exception {
  // constructors, etc
  String getCustomValue() { return "foo"; }
}

try {
  //...
} catch (MyException1|MyException2 e) {
  e.getCustomValue(); // won't work, as I expected
}

I won't be able to call getCustomValue(), even though the method is the same, because inside Java the above try/catch is supposed to actually be casting the MyException1/2 to Exception (that's how I understood the docs).

However, if I introduce an interface like this:

public interface CustomValueGetter {
  String getCustomValue();
}

public class MyException1 extends Exception implements CustomValueGetter /*...*/
public class MyException2 extends Exception implements CustomValueGetter /*...*/

and add it to both exceptions, Java is actually able to allow me to use that method. And then calling this is valid:

try {
  //...
} catch (MyException1|MyException2 e) {
  e.getCustomValue(); // does work
}

In short, my question is: what is actually happening here: (MyException1|MyException2 e).

What is e?

  • Is the closest superclass chosen as the type of e? This question asks about it and that's, supposedly, the answer. If so, then why is the interface CustomValueGetter "visible" when I access e? It shouldn't be if, in my case, e is an Exception.

  • And if not, if the real class is either MyException1 or MyException2 why am I not simply able to call the same method available for both of those classes?

  • Is e an instance of a dynamically generated class which implements all common interfaces of both exceptions and is of the nearest common supperclass type?

like image 210
Dariusz Avatar asked Aug 27 '15 06:08

Dariusz


People also ask

What type of exception can be ignored at compile time?

Runtime exceptions are ignored at the time of compilation.

Which subclass of throwable is checked at compile time?

Checked Exceptions These are the exceptions that are checked at compile time.

How do you handle two exceptions in single catch?

Java allows you to catch multiple type exceptions in a single catch block. It was introduced in Java 7 and helps to optimize code. You can use vertical bar (|) to separate multiple exceptions in catch block.

Can we handle multiple exceptions in single catch block?

Handling More Than One Type of Exception The catch clause specifies the types of exceptions that the block can handle, and each exception type is separated with a vertical bar ( | ). Note: If a catch block handles more than one exception type, then the catch parameter is implicitly final .


1 Answers

As Ischuetze said, e is looking for the class or interface that both exceptions do share. In your first example in can´t find a a sharing class despite the Exception class hence it is only able to use the methodes provided by it.

Changing your example to this code will be able to compile again.

public class MyException12 extends Exception {
    public String getCustomValue(){ return "boo"; };
}

public class MyException1 extends MyException12{
    public String getCustomValue() { return "foo"; };
}

public class MyException2 extends MyException12{
    // constructors, etc
    public String getCustomValue() { return "foo"; };
}

As in your Example with the interface, the Exceptions notifies that both MyException1 and MyException2 have MyException12 and hence are able to use it´s functions.

Here is a SO question answering the whole problem and what the type of e will be.

a quote from the link in the answer:

Changing the handling of exception types affects the type system in two ways: in addition to the usual type checking performed on all types, exception types undergo an additional compile time analysis. For the purpose of type checking, a catch parameter declared with a disjunction has type lub(t1, t2, ...) (JLSv3 §15.12.2.7) where the ti are the exception types the catch clause is declared to handle. Informally, the lub (least upper bound) is the most specific supertype of the types in question. In the case of a multi-catch exception parameter, the least upper bound of the types in question always exists since the types of all the caught exceptions must be subclasses of Throwable. Therefore, Throwable is an upper bound of the types in question, but it may not be the least upper bound since some subclass of Throwable may be a superclass (and thereby also a supertype) of the types in question and the exception types in question may implement a common interface. (A lub can be an intersection type of a superclass and one or more interfaces.) For the purpose of exception checking (JLSv3 §11.2), a throw statement (JLSv3 §11.2.2) that rethrows a final or effectively final catch parameter is treated as throwing precisely those exception types that:

like image 121
SomeJavaGuy Avatar answered Oct 13 '22 01:10

SomeJavaGuy