A common thing to do to utility classes is to give them a private constructor:
public final class UtilClass {
private UtilClass() {}
...
}
But unfortunately, some tools don't like that private constructor. They may warn that it's never called within the class, that it's not covered by tests, that the block doesn't contain a comment, etc.
A lot of those warnings go away if you do this instead:
public enum UtilClass {;
...
}
My question is: besides the unending hatred of future developers, what important differences are there between an enum with no values and a class with a private constructor in Java?
Note that I am not asking What's the advantage of a Java enum versus a class with public static final fields?. I'm not deciding between whether a list of things should be a bunch of constants or an enum, I'm deciding between putting a bunch of functions in a constructor-less class or a value-less enum.
Also note that I don't actually want to do this. I just want to know the trade-offs as part of general language knowledge.
For example, using an enum pollutes the autocomplete with useless methods like UtilClass.values()
. What other downsides are there? Upsides?
One benefit is that you're absolutely guaranteed that no instances can be created, even from inside the class.
A disadvantage is that this goes beyond the usual intent of enums. However, we already do this for singletons implemented with enums.
This bit from "Effective Java" by Joshua Bloch about such singletons also applies to utility classes:
...you get an ironclad guarantee that there can be no instances besides the declared constants. The JVM makes this guarantee, and you can depend on it.
Disclaimer: I have not used this pattern, and am not recommending for or against it.
Using enum
for something that's not actually an enum is ugly and confusing. I'd say that's enough reason not to do it.
The "utility class" pattern is perfectly legitimate. If your tools don't like it, that's a problem with the tools.
The following pattern in utility classes also provides ironclad guarantee that there can be no instances:
public abstract class Util {
private Util() { throw new Error(); }
... // static methods
}
Besides, you have no additional irrelevant static methods, provided by enums.
The only difference is that you can still call the constructor inside your class:
public final class UtilityClass {
public static final UtilityClass Instance = new UtilityClass();
private UtilityClass () {}
public static int Foo (int a, int b) {
return a+b;
}
}
But since you're the designer of that class, it wouldn't make any sense to break your own code contracts.
In general, most software design books I've ever read, are against using static methods. Unless they are really utility methods: in the sense they will never ever require any state. And even then, it's only a small effort to implement a Singleton pattern such that, when the time would come, you can assign state to it:
public final class UtilityClass {
public static final UtilityClass Instance = new UtilityClass();
private UtilityClass () {}
public int Foo (int a, int b) {
return a+b;
}
}
And calling it with UtilityClass.Instance.Foo(2,5);
. It would be way harder to perform an introduce state transformation later on in the coding process. Thus static methods are harder to maintain.
The reason why instances are useful is that you can use them in a lot of patterns like Strategy if at one occasion it depends on something what should be done,... By using static
methods, one makes the methods less dynamic because Java doesn't support method pointers (for good reasons). Thus non-static methods are more dynamic and useful.
Furthermore some security researchers argue that it is harder to analyze code with static
modifiers since they can be accessed from anywhere and the side effects are less predictable (for instance in an automatic security analysis tool): say you have an class that is not fully implemented, then you can still analyze the fields to know which methods it can access and thus analyze the possible side effects (network usage, file IO,...). This can generate a list of possible hazards per class that should be verified. At least if I understood the PhD dissertation of one of my fellow researchers correct. Thus non-static methods allow more modifier analysis.
To conclude: Java was built on the principle of object-oriented programming. This means that the "class world" is used by the compiler, and the "instance world" by the interpreter/runtime. I agree there are a lot of conflicts between the two words. But static
methods are in many/some cases a mistake to resolve such conflicts.