Skip to content

A Guide for Java Enum

Image: pexels.com

Enum is a special type in Java that allows for variables to use only values defined in a fixed and well-known list of values. Thus, it guarantees type safety, once the variable can be set to the values already defined by the items. You can see an enum as a special kind of Java class. Other important enum features are, seen later in the examples, are:

  • Enums can implement interfaces;
  • Enums have their own namespace;
  • Implicitly implements Serializable;
  • Implicitly implements Comparable;
  • Implicitly implements java.lang.Enum and cannot extends from another class;
  • To compare enums you can use == and equals().

You cannot create an enum by the new operator, once the constructors, if any, are private. As a result, an enum could be a replacement for String and Integer constants. More than this, it is possible to use enums in more complex solutions, as seen in this tutorial. For example, you can have multiple constructors in order to change the values of each item. Or you can use enums to implement singleton and strategy design patterns.

The enum methods you need to know are:

  • name(): a final method that returns the value of the constant;
  • toString(): returns the value of the constant, but can be overridden;
  • ordinal(): returns the position of the constant, starting by zero;
  • valueOf(String): creates an enum from a String value;
  • values() returns an array with the enum values.

That said, it is time for coding.

Simple Enum

This is the canonical example of an enum, with the predefined constants. The enum SimpleProtocol has the constants DHCP, HTTP, HTTPS, NFS.

public enum SimpleProtocol {

    DHCP, HTTP, HTTPS, NFS;

}

The simplest way of using an enum is:

SimpleProtocol dhcp = SimpleProtocol.DHCP;
System.out.println("Simple Protocol: " + dhcp);

It is possible to create an instance with the valueOf and Enum.valueOf:

SimpleProtocol nfs = SimpleProtocol.valueOf("NFS");
System.out.println("From value: " + nfs);
System.out.println("From enum: " + Enum.valueOf(SimpleProtocol.class, "HTTP"));

If you use the valueOf, You must check if the value exists in the constant list:

String value = "nfs";
try {
    System.out.println(SimpleProtocol.valueOf(value));
} catch (Exception e) {
    System.err.println("Invalid value: " + value);
}

And This is how we can use the values() method. Note the values of the ordinal() method. It is possible to iterate as a normal array, using streams and lambdas.

System.out.println("Values: " + Arrays.toString(SimpleProtocol.values()));

for (SimpleProtocol sp : SimpleProtocol.values()) {
    System.out.println("Value: " + sp + ". Position: " + sp.ordinal());
}

Arrays.asList(SimpleProtocol.values()).stream().forEach(System.out::println);

To use enums in a switch statement:

SimpleProtocol protocol = SimpleProtocol.valueOf("NFS");
switch (protocol) {
case DHCP:
    System.out.println("I am DHCP.");
    break;
case HTTP:
    System.out.println("I am HTTP.");
    break;
case HTTPS:
    System.out.println("I am HTTPS.");
    break;
case NFS:
    System.out.println("I am NFS.");
    break;
}

Once enums are constants, eventually you need to compare them in if-statements, like these:

if (SimpleProtocol.DHCP == dhcp) {
    System.out.println("We are equals.");
}

if (SimpleProtocol.DHCP.equals(dhcp)) {
    System.out.println("Yes, equals.");
}

Enum with Constructor and Field

Constructors are always private in enums, but the fields can have public access methods. Note that fields and methods must be after the list of constants.

public enum NamedProtocol {

    DHCP("Dynamic Host Configuration Protocol"), HTTP("Hypertext Transfer Protocol"),
    HTTPS("Hyper Text Transfer Protocol Secure"), NFS("Network File System");

    private NamedProtocol(String fullName) {
        this.fullName = fullName;
    }

    public String getFullName() {
        return fullName;
    }

    private String fullName;

}

So you can use that feature like this:

System.out.println("Full name: " + NamedProtocol.NFS.getFullName());

Enums and Interfaces

Enums can implement interfaces. Let’s consider the Descriptive interface:

public interface Descriptive {

    String getDescription();

    String getFullName();

}

Now, we can implement that interface on the DescriptiveProtocol and the needed methods.

package net.examples.enums;

public enum DescriptiveProtocol implements Descriptive {

    DHCP("Dynamic Host Configuration Protocol", "Dynamically assigns an IP address."),
    HTTP("Hypertext Transfer Protocol", "Foundation of data communication for the World Wide Web."),
    HTTPS("Hyper Text Transfer Protocol Secure", "Extension of the HTTP used for secure communication."),
    NFS("Network File System", "Distributed file system protocol.");

    private DescriptiveProtocol(String fullName, String description) {
        this.fullName = fullName;
        this.description = description;
    }

    @Override
    public String getDescription() {
        return description;
    }

    @Override
    public String getFullName() {
        return fullName;
    }

    private String description;
    private String fullName;

}

To use this feature is straightforward:

DescriptiveProtocol https = DescriptiveProtocol.HTTPS;
System.out.println("Description: " + https.getDescription());

Multiple Constructors

As seen, it is possible to use enums in creative ways, allowing us new alternatives, for example, multiple constructors. Note that the constant HTTP uses a different constructor, which is private SecureProtocol(String, boolean). In this code, you can see a new toString implementation and the static method getSecureProtocols, that uses lambdas and streams.

public enum SecureProtocol {

    DHCP("Dynamic Host Configuration Protocol"), HTTP("Hypertext Transfer Protocol", false),
    HTTPS("Hyper Text Transfer Protocol Secure"), NFS("Network File System");

    private SecureProtocol(String fullName) {
        this.fullName = fullName;
    }

    private SecureProtocol(String fullName, boolean secure) {
        this.fullName = fullName;
        this.secure = secure;
    }

    public String getFullName() {
        return fullName;
    }

    public boolean isSecure() {
        return secure;
    }

    private String fullName;
    private boolean secure = true;

    @Override
    public String toString() {
        return "Name: " + getFullName() + ". Is secure: " + isSecure();
    }

    public static List<SecureProtocol> getSecureProtocols() {
        return Arrays.asList(values()).stream().filter(SecureProtocol::isSecure).collect(Collectors.toList());
    }

}

And this is how we can use them. The toString can be accessed this way System.out.println(SecureProtocol.HTTP.toString()), or like this System.out.println(SecureProtocol.HTTPS). The getSecureProtocols returns a List to use a simple forEach lambda expression or a traditional for-statement to access it.

SecureProtocol.getSecureProtocols().stream().forEach(System.out::println);

Singleton Design Pattern

An enum is a good way of implementing the singleton design pattern. The constants are static. Hence it is guaranteed that we have just one instance of the enum and are also thread-safe. Let’s consider this example:

public enum Counter {

    INSTANCE;

    private int value;

    public void setValue(int value) {
        this.value = value;
    }

    public void process() {
        System.out.println(value);
    }

}

The INSTANCE constant is a singleton and can be used, as seen below. As a singleton, only the last value is shown.

Counter firstInstance = Counter.INSTANCE;
firstInstance.setValue(1);
firstInstance.process();

Counter secondInstance = Counter.INSTANCE;
secondInstance.setValue(2);
secondInstance.process();
firstInstance.process();

Abstract Methods

An enum can have abstract methods. In this case, every constant must implement it.

public enum NamedProtocolWithAbstractMethod {

    DHCP {
        @Override
        public String getFormattedName() {
            return "I am the Dynamic Host Configuration Protocol";
        }
    },
    HTTP {
        @Override
        public String getFormattedName() {
            return "I am the Hypertext Transfer Protocol";
        }
    },
    HTTPS {
        @Override
        public String getFormattedName() {
            return "I am the Hyper Text Transfer Protocol Secure";
        }
    },
    NFS {
        @Override
        public String getFormattedName() {
            return "I am the Network File System";
        }
    };

    public abstract String getFormattedName();
}

The usage is quite simple:

NamedProtocolWithAbstractMethod nfsAbs = NamedProtocolWithAbstractMethod.NFS;
System.out.println(nfsAbs.getFormattedName());

Conclusion

Enums are a convenient way to create constants in Java. Besides that, it is possible to use constructors, fields, implement interfaces, and abstract methods. As a subclass of java.lang.Enum, an enum has methods like name(), toString(), ordinal(), valueOf(String) and values().

References

https://docs.oracle.com/javase/tutorial/java/javaOO/enum.html

Leave a Reply

Your email address will not be published. Required fields are marked *