You must know the high-level Java enumeration features!
Program description DD 2021-06-25 01:54:36

JAVA enumeration , More useful than you think !

I often find myself in Java Enumeration is used in to represent a set of potential values for an object .

The ability to determine what values a type can have at compile time is a powerful ability , It provides structure and meaning for code .

When I first learned about enumeration , I thought they were just a tool to name constants , It's easy to use static constant strings ENUM_VAL_NAME replaced .

And then I found out I was wrong . The fact proved that ,Java Enumeration has quite advanced features , Can make the code clean 、 It's not easy to make mistakes. , Powerful .

Let's take a look Java Some advanced enumeration features in , And how to use these features to make the code simpler 、 More readable .

Enumerations are classes !

stay Java in , The enumeration is Object A subclass of . Let's look at the base class for all enumerations ,Enum ( Modified for brevity ).

public abstract class Enum<E extends Enum<E>>
implements Constable, Comparable<E>, Serializable {
private final String name;

public final String name() {
return name;
}

private final int ordinal;

public final int ordinal() {
return ordinal;
}

protected Enum(String name, int ordinal) {
this.name = name;
this.ordinal = ordinal;
}

public String toString() {
return name;
}

public final boolean equals(Object other) {
return this==other;
}

public final int hashCode() {
return super.hashCode();
}

public final int compareTo(E o) {
Enum<?> other = (Enum<?>)o;
Enum<E> self = this;
if (self.getClass() != other.getClass() && // optimization
self.getDeclaringClass() != other.getDeclaringClass())
throw new ClassCastException();
return self.ordinal - other.ordinal;
}
}

We can see , This is basically just a regular abstract class , There are two fields ,name and ordinal.

So enumerations are classes , So they have many of the features of regular classes .

We can provide instance methods for enumeration 、 Constructors and fields . We can rewrite toString(), But you can't rewrite hashCode() or equals(Object other).

Next, let's look at our enumeration example ,Operation

enum Operation {
ADD,
SUBTRACT,
MULTIPLY
}

This enumeration represents a Operation You can do this for two values , And will generate a result . About how to implement this function , Your initial idea might be to use switch sentence , As shown below :

 public int apply(Operation operation, int arg1, int arg2) {
switch(operation) {
case ADD:
return arg1 + arg2;
case SUBTRACT:
return arg1 - arg2;
case MULTIPLY:
return arg1 * arg2;
default:
throw new UnsupportedOperationException();
}
}

Of course , There will be some problems .

The first question is , If we add a new operation to our enumeration Operation in , The compiler won't tell us that the switch doesn't handle new operations properly .

What's worse is , If a lazy developer copies or rewrites the code in another class , We may not be able to update it .

The second problem is the default default, It's necessary in every program , Even though we know it will never happen in the right code .

This is because Java The compiler knows the first question above , And want to make sure that we can deal with unknowingly giving Operation New enumeration added to .

not so bad ,Java8 Functional programming provides us with a clean solution .

Function enumeration implementation

Because enumerations are classes , So we can create an enumeration field to hold the function that performs the operation .

But before we find a solution , Let's start with some refactoring .

First , Let's put the switch on enum Class .

 
enum Operation {
ADD,
SUBTRACT,
MULTIPLY;

public static int apply(Operation operation, int arg1, int arg2) {
switch(operation) {
case ADD:
return arg1 + arg2;
case SUBTRACT:
return arg1 - arg2;
case MULTIPLY:
return arg1 * arg2;
default:
throw new UnsupportedOperationException();
}
}
}

We can do that :Operation.apply(Operation.ADD, 2, 3);

Because we're starting from Operation The calling method , So we can change it to an instance method and use this, Rather than using Operation.apply() To achieve , As shown below :

public int apply(int arg1, int arg2) {
switch(this) {
case ADD:
return arg1 + arg2;
case SUBTRACT:
return arg1 - arg2;
case MULTIPLY:
return arg1 * arg2;
default:
throw new UnsupportedOperationException();
}
}

Use... Like this :Operation.ADD.apply(2, 3);

It looks better . Now let's go one step further , Completely eliminate... By using functional programming switch sentence .

enum Operation {
ADD((x, y) -> x + y),
SUBTRACT((x, y) -> x - y),
MULTIPLY((x, y) -> x * y);

Operation(BiFunction<Integer, Integer, Integer> operation) {
this.operation = operation;
}

private final BiFunction<Integer, Integer, Integer> operation;

public int apply(int x, int y) {
return operation.apply(x, y);
}

}

What I'm doing here is :

  • Added a field BiFunction<Integer, Integer, Integer> operation
  • use BiFunction Created for Operation Constructor for .
  • Call the constructor in the enumeration definition , And use lambda Appoint BiFunction<Integer, Integer, Integer>.

This java.util.function.BiFunction operation Fields are functions that take two arguments to ( Method ) References to .

In our case , Both parameters are int type , The return value is also int type . Unfortunately ,Java Parameterized types do not support primitives , So we have to use Integer.

because BiFunction Yes, it is @functioninterface The annotations , So we can use it Lambda Notation defines a .

Because our function takes two arguments , So we can use it (x,y) To designate them .

Then we define a single line method , It USES ->x+y Returns a value . This is equivalent to the following method , It's just simpler .

class Adder implements BiFunction<Integer, Integer, Integer> {
@Override
public Integer apply(Integer x, Integer y) {
return x + y;
}
}

Our new Operation The implementation takes the same way :Operation.ADD.apply(2, 3);.

however , This realization is better , Because the compiler will tell us when to add new Operation, This requires us to update the new function . If not , If we're adding new Operation Don't remember to update switch sentence , It's possible to get UnsupportedOperationException().

Key points

  • Enum The enumeration is Enum Extension class of .

  • Enum Enumeration can have fields 、 Constructors and instance methods .

  • Enum Enumeration fields can store functions . And lambdas In combination with , You can create clean 、 Secure implementation of enumeration specific functions , And enforce them at compile time ( Instead of using switch).

Here's an example of GitHub Address .(https://github.com/alex-power/java-enum-example)

In this paper, the reference :https://medium.com/javarevisited/advanced-java-enum-features-you-need-to-know-b516a191c7e2

Please bring the original link to reprint ,thank
Similar articles