'Why can't the instance member be accessed from the lambda of the enum constructor?

In the code below, I am trying to output the value of a symbol that is an instance variable of Operation from a PLUS constant.

But I can't access that variable.

What's the problem?

public enum Operation {
    PLUS("+", (x, y) -> {
        System.out.println(symbol);
        return x + y;
    }),
    MINUS("-", (x, y) -> x - y),
    TIMES("*", (x, y) -> x * y),
    DIVIDE("/", (x, y) -> x / y);

    Operation(String symbol, DoubleBinaryOperator op) {
        this.symbol = symbol;
        this.op = op;
    }

    public String getSymbol() {
        return symbol;
    }

    protected final String symbol;
    private final DoubleBinaryOperator op;

    public double apply(double x, double y) {
        return op.applyAsDouble(x, y);
    }
}



Solution 1:[1]

The lambda expression is not a member of the enum, so it cannot access member variables from the enum directly. It also has no access to protected and private members of the enum. Also, at the point where the lambda is passed to the constructor, the member variables of the enum are not in scope.

A possible solution is to pass symbol as a third parameter to the lambda expression, but that means you'll have to use a different functional interface than DoubleBinaryOperator.

For example:

interface CalculationOperation {
    double calculate(double x, double y, String symbol);
}

public enum Operation {
    PLUS("+", (x, y, symbol) -> {
        System.out.println(symbol);
        return x + y;
    }),
    MINUS("-", (x, y, symbol) -> x - y),
    TIMES("*", (x, y, symbol) -> x * y),
    DIVIDE("/", (x, y, symbol) -> x / y);

    Operation(String symbol, CalculationOperation op) {
        this.symbol = symbol;
        this.op = op;
    }

    public String getSymbol() {
        return symbol;
    }

    protected final String symbol;
    private final CalculationOperation op;

    public double apply(double x, double y) {
        return op.calculate(x, y, symbol);
    }
}

Solution 2:[2]

Alternatively:

import java.util.function.DoubleBinaryOperator;
import java.util.function.Supplier;


public class Test {

    public enum Operation {
        PLUS("+", (x, y) -> x + y, "verbose"),
        MINUS("-", (x, y) -> x - y),
        TIMES("*", (x, y) -> x * y),
        DIVIDE("/", (x, y) -> x / y);
        
        Operation(String symbol, DoubleBinaryOperator op) {
            this(symbol, op, null);
        }

        Operation(String symbol, DoubleBinaryOperator op, String command) {
            this.symbol = symbol;
            this.op = op;
            if("verbose".equalsIgnoreCase(command))
                operation = verboseWrapper;
            else
                operation = silentWrapper;
        }

        public String getSymbol() {
            
            return symbol;
        }

        protected String symbol;
        
        private DoubleBinaryOperator op;
        private Supplier<DoubleBinaryOperator> verboseWrapper = (() -> {System.out.println(symbol); return op; });
        private Supplier<DoubleBinaryOperator> silentWrapper = (() -> {return op; });

        private final Supplier<DoubleBinaryOperator> operation;
        
        public double apply(double x, double y) {
            
            return operation.get().applyAsDouble(x, y);
        }
    }
    
    public static void main(String [] args) {
                
        Operation plus = Operation.PLUS;
        
        plus.apply(1, 3);
        
        Operation minus = Operation.MINUS;
        
        minus.apply(1, 3);
    }

}

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Jesper
Solution 2