Proposal: Infer checked exceptions from private methods

Brian Goetz brian.goetz at oracle.com
Thu Mar 3 21:36:44 UTC 2022


While I understand the motivation for such a request, I suspect it would 
likely make things worse, not better.

When we did type inference for local variables, we deliberately 
restricted it to local variables only, not fields or methods, because 
methods and fields are part of a classes API, and we wouldn't want the 
API to subtly change based on implementation detail, which would cause 
linkage errors.

Clever folks observed: "but AHA, you could use inference for *private* 
method returns and fields without having that problem, why wouldn't you 
do that?"

And we did have a reason for that: simplicity.  By not coupling 
inference to complex other details such as accessibility, it is easier 
to reason about when inference can be used (developers hate when they 
can't easily understand which features can be used where), and more 
importantly, means that making a private method public is simply a 
matter of changing the accessibility, not rewriting the method header.  
Ad-hoc interactions between features (e.g., inference and accessibility) 
is a pernicious form of hidden complexity.

Supporting inference of exceptions here is very similar to inference of 
return type.

Such a feature is also likely to be misinterpreted; not all developers 
will immediately realize this is mere inference, they may well think it 
is "turning off checked exceptions" (and many of them will want to 
believe this.)  Which, for the vocal segment of Java users who think 
checked exceptions are the worst thing ever, would seem like a big slap 
in the face -- "you let me turn off checked exceptions, but only in the 
least important places!"

On 3/3/2022 8:08 AM, negora wrote:
> Hi:
>
> I've seen many programmers propagate all checked exceptions up the 
> call stack,
> from multiple private methods to the first non-private method of the 
> class.
> There, some exceptions are allowed to propagate, whereas others are 
> wrapped
> with one or more unchecked exceptions.
>
> So I would like to propose a variation of the `throws` clause, such as 
> `throws
> uncaught` or `throws *`, so that the compiler infers which checked 
> exceptions
> are thrown. **This feature would be limited to private methods,** so that
> developers are forced to think about their public APIs and don't let
> implementation details leak.
>
> Thanks to this, propagating exceptions inside a class would be super 
> easy and
> would not clutter the code so much. I work in big server applications 
> and some
> times the list of exceptions to "carry" between private methods is so 
> long,
> that even the simplest method takes multiple lines of code, making it 
> hard to
> read.
>
> In addition to this, if you changed the implementation in the future, 
> you would
> have not to worry much about the exceptions thrown by the private 
> methods,
> because you could make the necessary changes only in the non-private 
> methods.
>
> Example with irrelevant parts omitted:
>
> ```
> /* This method does nothing special. */
> public void addStudentToRepository (
>     String name,
>     String surname
>     Integer schoolID)
>     throws SchoolNotFoundException {
>
>   try {
>
>     ...
>     School school = findSchool (schoolID);
>     ...
>
>   } catch (UnavailableRepositoryException | WrongIDTypeException ex) {
>     throw new ImplementationException (ex);
>   }
>
> }
>
> /* Here is the interesting part. */
> private School findSchool (Integer id)
>     throws uncaught {
>         /* ^^^ This is equivalent to throw
>          * "UnavailableRepositoryException",
>          * "WrongIDTypeException",
>          * and "SchoolNotFoundException" separately.
>          */
>
>   School school = repository.findObject (id, School.class);
>                           /* ^^^ This throws
>                            * "UnavailableRepositoryException"
>                            * and  "WrongIDTypeException".
>                            */
>   if (school != null) {
>     return school;
>   } else {
>     throw new SchoolNotFoundException (id);
>   }
>
> }
> ```
>
> This example is very basic. I know that 
> `UnavailableRepositoryException` and
> `WrongIDTypeException` could inherit from a common 
> `RepositoryException`, but:
>
> 1. You lose the specific types of the exceptions.
>
> 1. Sometimes that's not an option, because the exceptions come from 
> different
> libraries or frameworks.
>
> Thank you!
>
> Best regards,
> negora.


More information about the amber-dev mailing list