Multi-catch and exhaustiveness check

Brian Goetz brian.goetz at oracle.com
Mon Aug 1 14:38:26 UTC 2022


First question: what is the type of `e` in your catch block?

You might think it is the union type MyAbstractException | 
MyUncheckedException, but in fact it is the least upper bound (LUB) of 
the two, which turns out to be RuntimeException, as per JLS 14.20:

> The declared type of an exception parameter that denotes its type as a 
> union with
> alternatives D1 | D2 | ... | Dn is lub(D1, D2, ..., Dn).

So your switch is a switch on a variable of type RuntimeException, and 
the switch is obviously not exhaustive. So the compiler is correct.

You might ask: why would we define the type of the catch formal like 
this?  Well, you have to go back to the context in which multi-catch was 
added.  This was the Project Coin days, where the scope was very limited 
-- including no type system changes -- and the use of LUB in this way 
was a trade-off that made it mostly acceptable.  The alternative would 
have been adding full-blown union types, which would not have been a 
small change (see this PhD thesis which outlines what would have been 
involved: https://scholarship.rice.edu/handle/1911/103594).









On 8/1/2022 8:28 AM, Thiago Henrique Hupner wrote:
> Hello all!
>
> I've played around with the exhaustiveness check and I'd like to
> discuss whether the following code should compile or it is right not 
> to compile.
>
> import java.util.*;
> import java.io.*;
>
> sealed abstract class MyAbstractException extends RuntimeException {
>     final static class MyException extends MyAbstractException {}
> }
>
> final class MyUncheckedException extends UncheckedIOException {
>     public MyUncheckedException() {
>         super(null);
>     }
> }
>
> public class SealedException {
>     public static void main(String[] args) {
>         try {
>             throw new MyUncheckedException();
>         } catch (MyAbstractException | MyUncheckedException e) {
>             switch (e) {
>                 case MyAbstractException.MyException a -> {}
>                 case MyUncheckedException b -> {}
>             }
>         }
>     }
> }
>
> As MyUncheckedExceptionh is final, and MyAbstractException.MyException 
> is the only implementation available for MyAbstractException, I guess 
> it is exhaustive, but the compiler disagrees.
>
> SealedException.java:23: error: the switch statement does not cover 
> all possible input values
>             switch (e) {
>             ^
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://mail.openjdk.org/pipermail/amber-dev/attachments/20220801/40afd670/attachment-0001.htm>


More information about the amber-dev mailing list