37

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?

Community
  • 1
  • 1
Craig Gidney
  • 17,763
  • 5
  • 68
  • 136
  • 11
    The main downside I see is that it's confusing. A developer expects an enum to be an enum, and to have instances, not a utility class masquerading as an enum. – JB Nizet Oct 28 '14 at 21:39
  • 1
    +1, but my utility classes are usually `final`. – mabi Oct 28 '14 at 21:39
  • 16
    I think the *unending hatred of future developers* is a strong enough reason to avoid such thing. It feels as a workaround to avoid tool warnings. If this pattern becomes common enough, the tools will eventually warn against it too. – afsantos Oct 28 '14 at 21:40
  • @mabi Whoops, forgot it for the example. Done. – Craig Gidney Oct 28 '14 at 21:40
  • 7
    Actually, an empty `enum` should trigger a *more severe* warning than a private default constructor. – mabi Oct 28 '14 at 21:42
  • 5
    `Enum`s are an under-rated feature of Java. They have all sorts of [uses](http://stackoverflow.com/a/71399/2517719) that most would never think of, and in my opinion the fact that most developers artificially limit their capabilities is not a good reason for you to do the same. That being said, it's not what I normally do. – Floegipoky Oct 28 '14 at 21:42
  • 3
    As a side note, I usually fill the empty constructor with `throw new AssertionError()`. It's *assertively* (?) wrong to ever instantiate an utility class. – afsantos Oct 28 '14 at 21:42
  • 1
    That is ... clever. I've never thought of that. I think it might be too clever, but I'm not sure. But I do know that if you have tools that are complaining that you don't have absolute 100% code coverage, those tools need to be adjusted. 100% coverage isn't a valid goal. And if they're complaining about an empty block with no comment in it, you could ... put a comment in it. Or throw an AssertionError as afsantos suggests. – David Conrad Oct 28 '14 at 21:51
  • @afsantos: I think the OP is refering to the *Singleton* pattern. So there is in fact an instance constructed once, but that's the only instance in the entire program. – Willem Van Onsem Oct 28 '14 at 22:02
  • @Strilanc: Do you mean your constructor is called once (to create **one** instance), or never? – Willem Van Onsem Oct 28 '14 at 22:03
  • 3
    @CommuSoft Never. This is a static utility class, not a singleton. – Craig Gidney Oct 28 '14 at 22:11
  • 1
    It may not be that bad. Have a glance on it , http://vanillajava.blogspot.com/2010/08/two-uses-for-enum-most-people-forget.html – Jimmy Oct 28 '14 at 22:18
  • @Jimmy: Indeed, many (security) researchers I've met advocate against the use of any `static`s (except the `main` of course). – Willem Van Onsem Oct 28 '14 at 22:20
  • @CommuSoft Maybe they were talking about a static local variable in C? Or static mutable variables? Marking a method as static generally just makes it easier to analyze, because it removes a way it can vary its behavior. *Maybe* you could use the fact that you need an instance of X as a weird form of scoping, but I've never seen that done. The main downside of static methods is that they're harder to mock. – Craig Gidney Oct 28 '14 at 22:29
  • @Strilanc: most analysis done tries to analyze what are the *possible access points*. They were definitely talking about side effects. I can't remember if the case was specific to Java, but the answer contains some additional arguments against `static`. It is a convenient solution for *lazy programmers* (not to be confused with lazy programming environments and no offense). But it has some severe downsides. – Willem Van Onsem Oct 28 '14 at 22:34

4 Answers4

34

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.

Mike Baranczak
  • 8,291
  • 8
  • 47
  • 71
31

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.

user1803551
  • 12,965
  • 5
  • 47
  • 74
Andy Thomas
  • 84,978
  • 11
  • 107
  • 151
  • 1
    Singleton with enums have a huge disadvantage of being serializable and if you have 2 options for an enum (cfg based) - you might end up (has happened!) with 2 distinct singletons. Singletons should never be serialized, but resolve on use. – bestsss Oct 30 '14 at 21:29
  • 1
    This seems tangential to the OP's question. That said, I'm not sure I understand what harm you see caused by allowing a singleton to be serialized. From the JLS: "the special treatment by the serialization mechanism ensures that duplicate instances are never created as a result of deserialization." IIUC, you could load the class and deserialize in multiple class loaders - but then the enum approach is no worse than others. – Andy Thomas Oct 30 '14 at 21:55
  • try smth like this `enum FactoryImpl implements SuperDuperFactory{ FastFactory{...}, MemoryEfficientFactort{....} }.` Now you have 2 possible instances of SuperDuperFactory but you can configure to use one at a time. However if you deserialize an instance with a reference to `SuperDuperFactory` you might end up with 2 active factories. If would have been an error `NotSerializableException` if the factory was not serializable. Of course the field reference to the factory should have been transient but such mistakes happen and enum helps mask 'em,since the're invisible if the factory is the same – bestsss Oct 30 '14 at 22:00
  • A singleton is a class with exactly one instance. You appear to have two instances. It looks more like you're using the strategy pattern than the singleton pattern. That seems unrelated to the OP's question. – Andy Thomas Oct 30 '14 at 22:21
  • Here is an example of what I talk about: http://pastebin.com/LDLyMikx there is exactly one instance of ByteBufferFactory. There could be different impl. based on the system configuration but effectively there would be a single impl... unless there is a different type gets to be desirialized. Pay attention that the enum is actually not publicly visible, so there is no other way to get a different instance. – bestsss Oct 31 '14 at 12:17
  • Last comment on this off-topic thread. See the prior comment. Your FactoryImpl class can be an enum -- but it is not a singleton, and it is not an example of a singleton implemented as an enum. Your ByteBufferFactory class could be a singleton implemented as enum. It could be configured during construction to hold a particular FactoryImpl. The serialized form of an enum constant is only the enum name. Deserialization will not result in multiple copies of the same enum constant. – Andy Thomas Oct 31 '14 at 16:52
9

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.

ursa
  • 4,404
  • 1
  • 24
  • 38
  • 1
    Yes, but how many people will read in the specs they are not supposed to call that constructor? Some people I know wasted hours before finding out that what they did was against the code contracts. I would advice making the constructor private. – Willem Van Onsem Oct 28 '14 at 22:17
  • 1
    Right, but that's not the question. Also... ironclad? If you don't mark the class final, you can perform child resurrection with the finalizer ([similar to this](http://codeblog.jonskeet.uk/2014/10/23/violating-the-smart-enum-pattern-in-c/)). – Craig Gidney Oct 28 '14 at 22:22
  • 1
    "Ironclad" is a little strong. Deserialization could create an instance, even with this constructor. And additional constructors could be added. – Andy Thomas Oct 28 '14 at 22:29
  • @AndyThomas: Good point, If one hacks into the java byte code one can derive the "class code" and let the deserializer do the work. Although, as argued by some (@Jimmy), `static` methods aren't really a gift to programmers. – Willem Van Onsem Oct 28 '14 at 22:30
  • @CommuSoft - You don't even have to hack into the Java byte code. If you have the source code, you could temporarily remove the throw, serialize an instance, and then deserialize it in production code. – Andy Thomas Oct 28 '14 at 22:41
  • @AndyThomas: Won't modifying the constructor result in a different "class signature" such that the deserializer doesn't know which class was serialized? – Willem Van Onsem Oct 28 '14 at 22:52
  • @CommuSoft - Fortunately, Java serialization is intended to support evolution of classes. And I tested before commenting. – Andy Thomas Oct 28 '14 at 23:19
  • just checked in code and fix details: mark class abstract and constructor private. would it be ironclad? – ursa Oct 28 '14 at 23:41
  • @ursa: I think not, because in the deserialization process, the constructor is never called: deserializing is a virtual machine hack on the constructor: the virtual machine initializes a new instance (without using a constructor, simply allocating memory) and after deserialization stores the values in that object (no setters used). If one tampers with the network, he can modify the content of the object and the VM/Constructor/Setters have no means to check this. It makes a `class` inherently less secure compared with an `enum`, regardless of what the programmer does. – Willem Van Onsem Oct 29 '14 at 00:55
  • but the class is abstract. I never heard about instances of abstract class. is it even possible in java? – ursa Oct 29 '14 at 04:50
  • You can’t deserialize a direct instance of an `abstract` class but you can deserialize an instance of a subclass of it. However, if your `abstract` class doesn’t implement `Serializable`, the specification mandates that the class have to have a default constructor accessible by the serializable subclass. So deserialization shouldn’t work here. And subclasses should be impossible anyway if all constructors are `private`. However, I would prefer declaring the class `final` to prevent subclasses. – Holger Oct 29 '14 at 10:19
  • 1
    @Strilanc: that is `C#`, not `Java`. Java never allowed cyclic constructors and even if you manipulate the byte code to have such a class file, resurrection wouldn’t work as [“An object `o` is not finalizable until its constructor has invoked the constructor for `Object` on `o` and that invocation has completed successfully (that is, without throwing an exception).”](http://docs.oracle.com/javase/specs/jls/se8/html/jls-12.html#jls-12.6.1). In other words, no `super()`, no `finalize`, i.e. no chance for this hack… – Holger Oct 29 '14 at 10:49
  • This can still be instantiated. Using an enum is ironclad, this is plasticclad. – Andreas Hartmann Jul 01 '19 at 14:12
5

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.

Willem Van Onsem
  • 443,496
  • 30
  • 428
  • 555
  • 1
    Humans make mistakes. So even though *it wouldn't make sense to break your own code*, it happens. Zero risk of error is preferable to tiny risk of error, particularly when you're writing lots of code. – Andy Thomas Oct 28 '14 at 22:39