Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/image-processing/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java:用lambdas替换开关。值得的?_Java_Coding Style - Fatal编程技术网

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

Java:用lambdas替换开关。值得的?,java,coding-style,Java,Coding Style,在检查事件时,使用带开关或if的代码块是常见的。当代码变得简单时,它可以是干净的代码,但似乎仍然有比需要的更多的行,并且可以使用lambdas进行简化 用if进行阻塞: if(action == ACTION_1){ doAction1(); } else if(action == ACTION_2){ doAction2(); } else { doDefaultAction(); } 带开关的闭塞: switch(action){ case ACTION_1

在检查事件时,使用带开关或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();
}
使用下面的实用程序类
使用lambda进行阻止:

with(action)
    .when(ACTION_1, this::doAction1)
    .when(ACTION_2, this::doAction2)
    .byDefault(this::doDefaultAction)
使用lambdas的代码更少,但问题是:它比其他代码更容易阅读吗?更容易维护?关于性能,lambdas是最差的,但是对于性能不重要的情况,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();
    }
}
带有{
私人最终身份证;
发现私有布尔运算;
私用(T id){
this.id=id;
}
具有(T id)的公共静态{
返回新的(id);
}
公共时间(T预期ID,动作){
如果(!actionFound&&id==expectedId){
actionFound=true;
action.execute();
}
归还这个;
}
默认情况下公共无效(操作){
如果(!actionFound){
action.execute();
}
}
@功能接口
界面作用{
void execute();
}
}

该开关更灵活,您可以使用不同数量的参数调用函数,也可以调用多个函数。您还可以更容易地表示两个案例何时导致相同的操作。更快的速度只是一个额外的好处

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

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

public With<T> when(Predicate<T> expected, Action action) {
    if (!actionFound && expected.test(id)) {
        actionFound = true;
        action.execute();
    }
    return this;
}
将开关更换为lambdas。值得吗

没有


因为在OO语言中,
开关
如果
/
否则
级联的替代品是多态性,而不是“流畅的API”。

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

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

例如:

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


执行此操作的一个选项是声明
预期的\u ID\u到\u ACTION的静态最终映射。然后你就可以
EXPECTED\u ID\u TO\u ACTION.getOrDefault(actionId,DEFAULT\u ACTION).execute()
,将丑陋的
开关
或多个
(如果
s)转换成一行。

当然看起来更整洁,但效率要低得多。而
开关
只是字节码中的跳转表;您的lambda方法每次都必须评估尽可能多的选项。只有你才能决定这个考虑对你是否重要。而且,这个-
id==expectedId
-是个糟糕的主意。你知道为什么…谢谢你的评论。同意您的看法,它的效率较低,使用
=
进行比较对对象不好,但它与
开关
的作用相同,因此在这种情况下,比较不应该是一个问题,“但它与开关的作用相同”气泡排序与其他排序算法相同;但是Java在调用
array.sort
Collections.sort
时不使用冒泡排序。。。并非所有正确的算法都是相等的。错误的-这就是为什么我说这是一个糟糕的想法。当一个开关将取消装箱原语时,你的泛型将把它们装箱——这意味着即使是任何一个也不会像你期望的那样工作。不要忘记
switch
支持
String
。你说得对,switch更灵活,许多情况可以组合成一个。在这种情况下,带有
类的
没有任何优势。我对你关于谓词的想法很感兴趣,你能给我举个例子吗?@IgnaciotomasRespo当然,我添加了一个例子。哇,这越来越好了。我喜欢对条件使用谓词。谢谢你的例子!仍然比
开关
差得多,但比建议的方法要好。@Boristespider不同意。
开关中的多个
大小写
块(>10)看起来很难看。此外,如果需要,这种方法允许在运行时更改分支行为。字节码跳转表将吃掉
映射
作为早餐。@Boristespider您是对的,性能vise它仍然比
开关
慢得多(如果我们谈论的是合理数量的分支)。感谢您指出这一点,答案已编辑。关于性能,您是对的,非常感谢链接到JEP!令人惊讶的是,LISP自50多年来已经拥有的东西(表达式的体面条件构造,而不仅仅是语句)终于来到了Java。一个可读的,更灵活的三元运算符替换@哈利路亚@IgnacioTomasCrespo和构造的另一个缺点:编译器在理解
if
switch
语句的控制流方面非常聪明:它们可以识别死代码,警告不完整的案例列表,等等。“我认为你们班不可能做到这一点。”拉尔夫·勒贝霍夫说得很好,这是另一个需要考虑的不利因素。谢谢完全同意多态性和switch语句。应该是首先考虑的。但在某些情况下,IMHO更像样板,模式也没有帮助。@IgnacioTomasCrespo将配置代码与执行代码分离是polymor的“我的个人杀手”功能
String formatted = switch (s) {
    case null -> "(null)";
    case "" -> "(empty)";
    default -> s;
}