[sealed] Sealed interface as a utility class?

Tagir Valeev amaembo at gmail.com
Fri Oct 18 09:02:26 UTC 2019


A utility class (a class that has only static members) is a ubiquitous
Java pattern. They are used in JDK, common third-party libraries and
applications. Usually, it's a final class. Since Java 8 (static
methods were introduced in the interface) it's possible to convert a
utility class to an interface. There are a number of advantages:

- It cannot be instantiated, by interface definition. As a result, you
don't need to create an ugly constructor like `private MyUtils()
{throw new UnsupportedOperationException();}`
- If you care much about code coverage, now you would have very bad
times trying to cover this constructor (some people do this!). Declare
it as an interface, and the problem is gone.
- No need to specify `static final` on the fields -- less visual noise
- No need to specify `static` on nested classes -- less visual noise
- You cannot accidentally declare a non-static member: it will be a
compilation error, and IDE will highlight it immediately suggesting a
fix. My experience shows that people indeed sometimes mistakenly
declare a non-static member in a utility class and realize this only
on the first usage. This is frustrating (why I don't see the
completion option? I just added this method, I know it's there! Is my
IDE drunk?) and takes time to fix.
- You cannot accidentally declare a non-static field or a non-static
nested class. You simply cannot.

Unfortunately one may implement such an interface which is not what we
would like to allow. In fact, such an approach was used in early Java
versions (until import static was introduced in Java 5) to use
interfaces that declare only constants (this is a subset of utility
classes). Now it's considered an anti-pattern to implement such an
interface [1].

Having sealed classes we may declare such an interface as a sealed and
provide no implementations at all, making it effectively final.
Unfortunately (or not), the latest spec draft [2] explicitly disables
this (9.1.4):

> It is a compile-time error if a sealed interface has no permitted subtypes.

This could be worked around introducing a bogus implementor inside:

public sealed interface MyUtils {
  private final class X implements MyUtils {} // just to make a compiler happy
  // static members follow

This will undermine the first advantage, as the bogus class should
again have the throwing constructor. However, you still have less
visual noise, and you've got protection against an accidental
non-static member. So we may expect that people will (ab)use this

The question is: whether should we support this or not? If yes, we
could lift the restriction on sealed interfaces without permits (which
essentially allows creating final interfaces). We could go further and
while allowing such interfaces we may disable any instance or default
methods inside (as nobody could call them anyway) which would make the
thing even more robust, and everybody would know that final interface
is a utility class.

If we don't support this, probably we should spell this out somewhere.
If somebody going to write a programmer's guide to sealed classes
(similar to TextBlocks one [3]), probably it's a good point to

A good alternative would be to invent a special syntax for utility
classes like `utlity class MyUtils {}`. This adds a few restrictions:
- All members are implicitly static; static modifier is allowed but
not necessary
- All fields are implicitly final, like in interfaces
- Constructors and instance initializers are disallowed
- Inheritors and instantiation is disallowed
- A `utility` modifier could be obtained via reflection
This would be a nice alternative, and there will be no reason to abuse
other language features.

With best regards,
Tagir Valeev.

[1] https://en.wikipedia.org/wiki/Constant_interface
[2] http://cr.openjdk.java.net/~gbierman/jep360/jep360-20190830/specs/sealed-types-jls.html
[3] https://cr.openjdk.java.net/~jlaskey/Strings/TextBlocksGuide_v9.html

More information about the amber-spec-experts mailing list