This entry deals with defining abstract methods in Java enums and writing their behavior. (The one written in Effective Java 3rd edition is almost the same. Make a note of what you tried.)
Java enums allow you to define methods as well as values.
Pattern that defines only the value
    enum Operator {
        PLUS, SUBTRACT, MULTIPLY, DIVIDE, NONE
    }
On the other hand, you can define a method for each value and write it as shown in the figure below.
    enum Operator {
        PLUS {
            @Override
            BigDecimal apply(@NonNull BigDecimal lhs, @NonNull BigDecimal rhs) {
                return lhs.add(rhs);
            }
        },
        SUBTRACT{
            @Override
            BigDecimal apply(@NonNull BigDecimal lhs, @NonNull BigDecimal rhs) {
                return lhs.subtract(rhs);
            }
        },
        MULTIPLY {
            @Override
            BigDecimal apply(@NonNull BigDecimal lhs, @NonNull BigDecimal rhs) {
                return lhs.multiply(rhs);
            }
        },
        DIVIDE {
            @Override
            BigDecimal apply(@NonNull BigDecimal lhs, @NonNull BigDecimal rhs) {
                return lhs.divide(rhs, BigDecimal.ROUND_UNNECESSARY);//;
            }
        },
        NONE {
            // allow null for rhs
            @Override
            BigDecimal apply(@NonNull BigDecimal lhs, BigDecimal rhs) {
                return lhs;
            }
        };
        abstract BigDecimal apply(BigDecimal lhs, BigDecimal rhs);
    }
In "abstract BigDecimal apply (BigDecimal lhs, BigDecimal rhs);" in enum, the method to be defined for all values is specified, and the method is overridden when each value is declared.
(Supplement) In the above source, "@NonNull" is one of annotations provided by lombok that implements Null check. is.
If you define an enum in the above form, for example, the following method
    public synchronized BigDecimal pushEvalButton() {
        var v = new BigDecimal(sb.toString());
        switch(currentOperator) {
            case PLUS: {
                v = stack.add(getCurrentValue());
                break;
            }
            case SUBTRACT: {
                  v = stack.subtract(getCurrentValue());
                  break;
            }
            case MULTIPLY: {
                  v = stack.multiply(getCurrentValue());
                  break;
            }
            case DIVIDE: {
                  v = stack.divide(getCurrentValue(), BigDecimal.ROUND_UNNECESSARY);//
                  break;
            }
            case NONE: {
                return v;
            }
            default: {
                throw new RuntimeException("Not defined.");
            }
        }
        currentOperator = Operator.NONE;
        replaceBuffer(v.toPlainString());
        clearStack();
        return v;
    }
You can write clearly as follows.
    public synchronized BigDecimal pushEvalButton() {
        var v = new BigDecimal(sb.toString());
        if(Operator.NONE == currentOperator) {
            return v;
        }
        v = currentOperator.apply(stack, getCurrentValue());
        currentOperator = Operator.NONE;
        replaceBuffer(v.toPlainString());
        clearStack();
        return v;
    }
Since the content has moved to the enum method, it is natural that the code is reduced from the original method, but I felt that the following are merits. --I was able to expel the default in the switch --By using enum methods in other places, the processing is put together in one place.
In this entry, I explained how to define abstract methods in Java enum and write their behaviors with an example.
See [This commit] on GitHub (https://github.com/hrkt/commandline-calculator/commit/47e7b05075c2bb632b9bdabdf044ab3b5cefdeee) for an example of the difference above.
Recommended Posts