Java:用 lambda 表达式替换 switch。值得?

Java: replace switch with lambdas. Worth it?

在检查事件时,将代码块与 switch 或 if 结合使用是很常见的事情。它可以是简洁的代码,但看起来仍然比需要的行多,并且可以使用 lambdas 进行简化。

阻止如果:

if(action == ACTION_1){
    doAction1();
} else if(action == ACTION_2){
    doAction2();
} else {
    doDefaultAction();
}

带开关的块:

switch(action){
    case ACTION_1:
        doAction1();
        break;
    case ACTION_2:
        doAction2();
        break;
    default:
        doDefaultAction();
}

使用以下实用程序 class With 使用 lambda 进行阻止:

with(action)
    .when(ACTION_1, this::doAction1)
    .when(ACTION_2, this::doAction2)
    .byDefault(this::doDefaultAction)

使用 lambda 的代码更少,但问题是:它比其他的更容易阅读吗?更容易维护?关于性能 lambdas 是最差的,但对于性能不重要的情况,lambdas 版本比 switch/if 块短。

那么,你怎么看呢?也许有比这更短的 Kotlin 方法,我试着只关注 java,我喜欢 Kotlin,但编译对于我的项目来说仍然太慢了。

当块必须 return 特定值时,可以使用类似的实用程序 class。

仅供参考,lambda 的 class 在这里,我没有检查错误,只是为了这个例子快速完成:

public class With<T> {

    private final T id;
    private boolean actionFound;

    private With(T id) {
        this.id = id;
    }

    public static <T> With<T> with(T id) {
        return new With<>(id);
    }

    public With<T> when(T expectedId, Action action) {
        if (!actionFound && id == expectedId) {
            actionFound = true;
            action.execute();
        }
        return this;
    }

    public void byDefault(Action action) {
        if (!actionFound) {
            action.execute();
        }
    }

    @FunctionalInterface
    interface Action {
        void execute();
    }
}

开关更加灵活,您可以使用不同数量的参数调用函数,或者调用多个函数。您还可以更轻松地表示两种情况何时会导致相同的操作。它更快的事实只是一个好处。

所以从这个意义上说,我不确定你的 With class 到底在添加什么。

但是,switch 可以使用的类型数量有限。也许你的 With class 如果你要传递它谓词而不是执行简单的引用相等,那么你的 With class 会被证明更有用,例如:

public With<T> when(Predicate<T> expected, Action action) {
    if (!actionFound && expected.test(id)) {
        actionFound = true;
        action.execute();
    }
    return this;
}

示例用法:

final String test = "test";

with(test)
    .when(String::isEmpty,      this::doAction1)
    .when(s -> s.length() == 3, this::doAction2)
    .byDefault(this::doDefaultAction);

replace switch with lambdas. Worth it?

没有

因为在 OO 语言中 switchif/else 级联的替换是 多态性 ,而不是 "fluent API".

正如一对夫妇所说,用复合方法代替 switch 效率较低。根据您的用例,使用您的实现甚至可能是值得的。

有趣的是,Oracle 实际上计划在 switch 语句中实施 lambda,如 this recent JEP.

中所示

示例:

String formatted = switch (s) {
    case null -> "(null)";
    case "" -> "(empty)";
    default -> s;
}

执行此操作的一个选项是声明 static final Map<T, Action> EXPECTED_ID_TO_ACTION。然后你就可以 EXPECTED_ID_TO_ACTION.getOrDefault(actionId, DEFAULT_ACTION).execute(),把丑陋的 switch 或多个 if 变成单行。