Java:用lambdas替换开关。值得?

时间:2018-02-02 14:53:30

标签: java coding-style

在检查事件时使用带有switch或if的代码块是常见的事情。它很简单,可以是干净的代码,但似乎仍然有比所需更多的行,并且可以使用lambdas进行简化。

阻止if:

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();
}

使用下面的实用程序类With阻止lambda:

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

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

那么,你怎么看?也许Kotlin的方式比这短,我只关注java,我喜欢Kotlin,但编译对我的项目来说仍然太慢。

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

仅供参考,lambdas的类在这里,我没有检查错误,只是为了这个例子快速做到了:

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();
    }
}

4 个答案:

答案 0 :(得分:2)

交换机更灵活,因为您可以使用不同数量的参数调用函数,或者调用多个函数。您还可以更轻松地表示两个案例何时导致相同的操作。它更快的事实只是一个奖励。

所以从这个意义上来说,我不确定你的With班级真正添加了什么。

但是,switch可以使用的类型有限。如果你传递谓词而不是执行简单的引用相等,那么你的With类可能会更有用,例如:

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);

答案 1 :(得分:2)

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

有趣的是,Oracle实际上计划在switch语句中实现lambdas,如this recent JEP中所示。

示例:

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

答案 2 :(得分:1)

  

用lambdas替换开关。值得吗?

没有

因为在OO语言中,switchif / else级联的替换是多态,而不是&#34;流畅的API&#34 ;

答案 3 :(得分:0)

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