Why does Java allow null value to be assigned to an Enum?

JavaEnums

Java Problem Overview


This is more of a design question, so no code. I could post code of creating an Enum and assigning it to null if you want me to do it. :))

I've been thinking a lot about this lately, but can't come up with one good reason. The Enum constants are implicitly static and final. Enum is meant to say - "I can take a value of one of the constants present in me". Why allow Enum to have a null value? Why not implicitly default the Enum's value to a Enum.DEFAULT or Enum.None? Isn't this a better approach than allowing the Enum to be null?

Java Solutions


Solution 1 - Java

Firstly null means non-existence of an instance. Providing a default constant like DEFAULT or NONE, will change that meaning. Secondly, why would you need something default to represent what seems to be non-existent? That is the purpose of null. Basically, you would have to initialize and store an extra object, which shouldn't even exist whatsoever.

BTW, it's not a language choice. It's completely on you how you implement your enum. You can provide another constant like DEFAULT, or UNKNOWN in your enum, and avoid the assignment of null to the reference in your code. This is famously known as Null Object Pattern. But saying that the null assignment should itself be compiler error, then I would say, since an Enum is anyways compiled to a Class, so it would be perfectly valid to use null to represent non-existence of an instance.

One pitfall of allowing null though is with the usage of enum in switch-case. The below code will throw NPE, even with a default case:

public class Demo {
	enum Color {
		WHITE, BLACK;
	}
	
	public static void main(String[] args) {
		Color color = null;
		
		switch (color) {    // NPE here
		case WHITE: break;
		case BLACK: break;
        default: break;     // null value does not fall into the default
		}
	}
}

Java does not allow a case null: either, producing the following compile error:

> an enum switch case label must be the unqualified name of an enumeration constant

Solution 2 - Java

Java allows any reference to be null, and references to enums aren't so special that a special case needs to be made to prevent it, or to provide another version of behaviour that is already well-specified and well-understood. Null is already a perfectly adequate sentinel value: we don't need another one.

Neither of your suggestions is convincing, as they would both require addition of yet further features to support them.

In any case it is several years too late to start debating the point.

Solution 3 - Java

I think, Enum.DEFAULT means that your enum variable contains a value, but null doesn't. If it's null it can be interpreted that it has no value, you can't invoke non-static methods on it for example.

Solution 4 - Java

You can add behaviour to your enums (Domain Driven Design), for instance add a public method named prettyPrint() that returns a String based on your enum value. How a default / null value can provide an implementation of this custom method?

If you want to represent null with an enum, then you'll have to explicit this by using a null object pattern manually with a NONE value and a custom implementation for prettyPrint() based on NONE value.

Solution 5 - Java

Old, I know. I'm half-in Java.

> Why allow Enum to have a null value?

There are few use cases, I believe. For example, we need to initialize an enum variable to tell us it's not really part of the enum, but we can change its value later, so that it is part of it. If there was no way to initialize an enum variable as null, then we would pollute the enum definition. So, in my opinion, fields such as LibEnum.NONE messes libraries. For example, you don't want one to use LibEnum.NONE as parameters for methods, between others.

I found it useful in my lexical scanner, among with keywords and punctuators. Suppose you've an identifier "blah". You then want to check if it's any keyword.

private Keywordv getKeywordValue(String id)
{
	switch (id.length())
	{
		case 2:
		{
			switch (id)
			{
				case "do": return Keywordv.DO;
				case "if": return Keywordv.IF;
				case "is": return Keywordv.IS;

				// ...
			}

			break;
		}

		// ...
	}

    return null;
}

Thanks to null, it's then easy to verify whether the identifier is not a keyword.

id == null

Otherwise we'd have to define something like Keywordv.__NULL

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionTheLostMindView Question on Stackoverflow
Solution 1 - JavaRohit JainView Answer on Stackoverflow
Solution 2 - Javauser207421View Answer on Stackoverflow
Solution 3 - JavaPhilip VoronovView Answer on Stackoverflow
Solution 4 - JavazenbeniView Answer on Stackoverflow
Solution 5 - JavaKlaiderView Answer on Stackoverflow