Reducing "exception is never thrown in body of corresponding try statement" Error to a Warning

Vitaly Davidovich vitalyd at gmail.com
Sun Oct 20 22:56:04 UTC 2019


Hi Mike,

On Sun, Oct 20, 2019 at 6:36 PM Mike Duigou <openjdk at duigou.org> wrote:

> Hello all;
>
> As part of my Oracle CodeOne talk "Exceptions 2020" I made two proposals
> for improving Java exceptions. One of the proposals was to remove the
> compile time error produced when and exception is caught that is not
> thrown by the enclosed statements. Specifically I am proposing the
> removal of the following section from JLS 11.2.3
>
>      "It is a compile-time error if a catch clause can catch checked
> exception class E1
>       and it is not the case that the try block corresponding to the
> catch clause can
>       throw a checked exception class that is a subclass or superclass of
> E1, unless E1
>       is Exception or a superclass of Exception."
>
> The advantage of removal of this rule is that removal allows API authors
> to better document the actual exceptions thrown by constructors and
> methods. Vestigial or inaccurate throws specifications can be eliminated
> without "breaking" calling code. This makes it easier to evolve the API
> by narrowing (including to empty), the exception specification of method
> without impacting existing code which uses the API.

Altering the checked exception throws clause is a contract change of the
method/ctor.  It’s not too dissimilar from changing the return value
(afterall, exceptions are just a side channel for return values).

I understand that people, in general, have a harder time designing checked
exception APIs “properly”, and thus this type of churn is more likely there
than normal method return types.  But, given it’s a contract change
nonetheless, I don’t see how weakening the check to a warning results in
better/robust/bug-free/etc code.  It sure makes the author’s life easier,
but that’s likely not where the focus should be.

>
>
> To allow application authors to clean up dead code an equivalent warning
> would still be provided and probably should be encouraged by the JLS
> specification. The warning would alert them that the catch clause will
> not be executed.

A good amount of projects I’ve worked on build with -Werror.  As such, a
hard error vs warning doesn’t matter - it’s a disruption either way, but as
mentioned above, a worthwhile one (IMO).

Given the JVM itself doesn’t care/know about checked exceptions, such
changes break source compatibility but allow binaries (bytecode) to
continue running.  That seems like the right compatibility knob, at least
given today’s Java.

>
>
> As an API author I have been frustrated many times by being unable to
> reduce or remove a method's exception specification without causing
> compatibility issues for my users and I have also been frustrated when
> libraries did choose to alter their method exception specifications and
> "broke" my code which caught the no longer thrown exceptions. Does this
> seem like a feature/change worth pursuing?
>
> Cheers,
>
> Mike
>
> The changes to javac needed to accomplish this change are quite simple:
>
> diff --git
> a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Flow.java
> b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Flow.java
> index 0c1fead9a4..f7793d0605 100644
> --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Flow.java
> +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Flow.java
> @@ -1271,7 +1277,7 @@ public class Flow {
>               } else if (!chk.isUnchecked(pos, exc) &&
>                       !isExceptionOrThrowable(exc) &&
>                       !chk.intersects(exc, thrownInTry)) {
> -                log.error(pos, Errors.ExceptNeverThrownInTry(exc));
> +                log.warning(pos, Warnings.ExceptNeverThrownInTry(exc));
>               } else {
>                   List<Type> catchableThrownTypes =
> chk.intersect(List.of(exc), thrownInTry);
>                   // 'catchableThrownTypes' cannnot possibly be empty -
> if 'exc' was an
> diff --git
> a/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/compiler.properties
>
>
> b/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/compiler.properties
> index 1f29df0704..e29b5583e4 100644
> ---
>
> a/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/compiler.properties
> +++
>
> b/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/compiler.properties
> @@ -533,10 +533,6 @@ compiler.err.error.reading.file=\
>   compiler.err.except.already.caught=\
>       exception {0} has already been caught
>
> -# 0: type
> -compiler.err.except.never.thrown.in.try=\
> -    exception {0} is never thrown in body of corresponding try
> statement
> -
>   # 0: symbol
>   compiler.err.final.parameter.may.not.be.assigned=\
>       final parameter {0} may not be assigned
> @@ -2019,6 +2015,14 @@ compiler.warn.unchecked.generic.array.creation=\
>   compiler.warn.unchecked.varargs.non.reifiable.type=\
>       Possible heap pollution from parameterized vararg type {0}
>
> +# 0: type
> +compiler.warn.except.never.thrown.in.try=\
> +    exception {0} is never thrown in body of corresponding try
> statement
> +
>   # 0: symbol
>   compiler.warn.varargs.unsafe.use.varargs.param=\
>       Varargs method could cause heap pollution from non-reifiable
> varargs parameter {0}
>
-- 
Sent from my phone


More information about the jdk-dev mailing list