用BinaryOperator替换switch

8

我将尝试用BinaryOperator函数接口替换常见的算术运算开关。

基本方法如下:

private static int computeOne(int res, String operand, String operation) {
    int number = Integer.parseInt(operand);

    switch (operation) {
        case "+":
            res += number;
            break;
        case "-":
            res -= number;
            break;
        case "*":
            res *= number;
            break;
        case "/":
            res = (number != 0 ? res / number : Integer.MAX_VALUE);
            break;
        default:
            res = 0;
            System.out.println("unknown operation");
    }

    return res;
}

据我所知,需要编写类似以下的内容:

BinaryOperator<Integer> action = (a,b) -> computeExpression(a + operation + b);
action.apply(res, operand);

但我不明白如何避免在computeExpression中使用switch,这与computeOne相同。


我必须承认,即使有一个被接受的答案,我也不理解这个问题。computeExpression似乎只是模糊地与ComputeOne相关,操作数和操作是字符串,原因不明确。限制是什么(操作是变量?String类型?),目标是什么?将字符串转换为Int似乎不是问题,那为什么要这样做?a + operation + b看起来会得到“42*14”。为什么要合并它们,当你后来需要拆分它们时? - user unknown
@userunknown,我认为他的意思是将computeExpression(a, operation, b)的签名与computeOne相似。 - Andrew Tobilko
2个回答

8
你可以为每个算术操作定义一个 BinaryOperator<Integer>
// a = operand 1
// b = operand 2
(a, b) -> a * b;
(a, b) -> a + b;
(a, b) -> a / b;
(a, b) -> a - b;

然后您可以应用一个传递2个参数的操作:

// result = operation.apply(a, b);
int result = ((BinaryOperator<Integer>) ((a, b) -> a * b)).apply(2, 2);

我会使用一个枚举来列举这些操作:

class Test {

    public static void main(String[] args) {
         System.out.println(computeOne(4, "2", "/"));  // 2
         System.out.println(computeOne(4, "2", "*"));  // 8
         System.out.println(computeOne(4, "2", "-"));  // 2
         System.out.println(computeOne(4, "2", "+"));  // 6
    }

    private static int computeOne(int res, String operand, String operation) {
        return Operation.getOperationBySymbol(operation)
                        .getBinaryOperator()
                        .apply(res, Integer.parseInt(operand));
    }

    private enum Operation {
        // operation = symbol, action
        MULTIPLICATION("*", (a, b) -> a * b),
        ADDITION("+", (a, b) -> a + b),
        SUBTRACTION("-", (a, b) -> a - b),
        DIVISION("/", (a, b) -> a / b);

        private final BinaryOperator<Integer> binaryOperator;
        private final String symbol;

        Operation(String symbol, BinaryOperator<Integer> binaryOperator) {
            this.symbol = symbol;
            this.binaryOperator = binaryOperator;
        }

        public BinaryOperator<Integer> getBinaryOperator() {
            return binaryOperator;
        }

        public String getSymbol() {
            return symbol;
        }

        public static Operation getOperationBySymbol(String symbol) {
            for (Operation operation : values()) {
                if (operation.getSymbol().equals(symbol)) {
                    return operation;
                }
            }

            throw new IllegalArgumentException("Unknown symbol: " + symbol);
        }
    }

}

您还可以使用 BiFunction<BinaryOperator<?>, Pair<?, ?>, ?> 来“简化”它:
// BiFunction<Operator, Operands, Result>
// Operator = BinaryOperator<?>
// Operands = Pair<?, ?>
BiFunction<BinaryOperator<Integer>, Pair<Integer, Integer>, Integer> f = 
    (operator, operands) -> 
        operator.apply(operands.getKey(), operands.getValue());

f.apply((a, b) -> a + b, new Pair<>(2, 2)); // 4

3
算术运算符不能是变量。
使用函数接口或实际代码中的无接口,您将具有相同的约束:将String运算符转换为算术运算符。

此外,在computeOne()中,您接受一个int和两个String作为参数,并返回一个int
BinaryOperator<Integer>接受两个Integer并返回一个Integer
因此它不兼容。
您需要一个TriFunction但它不存在。
要么创建自己的函数接口,例如TriFunction<T,U,V,R>,要么减少传递给函数的参数数量。

这里是一个示例,使用枚举Operator结合BiFunction执行与实际方法相同的操作。
请注意,由于运算符现在由负责执行函数的枚举Operator表示,因此函数现在只需要两个参数:您将其转换为intIntegerString
因此,BiFunction<Integer, String, Integer>就可以了。

public enum Operator{
    ADD("+", (a,b) -> a + Integer.parseInt(b)), 
    SUBSTRACT("-", (a,b) -> a - Integer.parseInt(b)),
    MULTIPLY("*", (a,b) -> a * Integer.parseInt(b)),
    //       ...
    DEFAULT("", (a,b) -> 0);

    public BiFunction<Integer, String, Integer> function;
    private String symbol;

    Operator(String symbol, BiFunction<Integer, String, Integer> function){
        this.symbol = symbol;
        this.function = function;
    }

    public int compute(int actualValue, String operand){
        return function.apply(actualValue, operand);
    }

    public static Operator of(String symbol) {
        for (Operator value : values()) {
            if (symbol.equals(value.symbol)) {
                return value;
            }
        }

        return Operator.DEFAULT;
    }

}

您可以创建这样一个操作:
int res = 10;
String operand = "15";
String symbol = "+";
res = Operator.of(symbol).compute(res, operand);

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接