可选vs if / else-if性能Java 8

Pan*_*s K 10 java performance if-statement optional java-8

您好,我有两个代码示例

if / else if / else语句

private Object getObj(message) {
        if (message.getA() != null)
            return message.getA();
        else if (message.getB() != null)
            return message.getB();
        else if (message.getC() != null)
            return message.getC();
        else return null;
}
Run Code Online (Sandbox Code Playgroud)

可选陈述

private Optional<Object> wrap(Object o){
    return Optional.ofNullable(o);
}

private Object getObj(message) {
    return  wrap(message.getA())
            .orElseGet(() -> wrap(message.getB())
            .orElseGet(() -> wrap(message.getC())
            .orElse(null)));
}
Run Code Online (Sandbox Code Playgroud)

所以我的问题是,这两者在性能方面如何比较(我在实际代码中大约有15-20条if-else语句)?

值得重构代码的可读性和性能,还是滥用可选选项?

另外,如果if / else-if语句增长到100+,性能损失会是多少?

提前致谢

Lin*_*ica 16

不要将Optionals用于条件逻辑。

它们被设计为从一种方法中返回,以指示可能不存在的值

仅仅因为您可以将它们很好地链接成一行并不意味着它是可以理解的。您实际上也一无所获。性能开销可能很大。在最坏的情况下,N将创建对象然后将其丢弃。只需呆在您的“正常” if-else锁链上。


退一步,问自己为什么需要15-20 if-else语句,而不是寻找使当前代码更具可读性的方法。你能分解一些逻辑吗?为什么首先需要为具有多个可能具有不同类型的多个不同字段使用一个吸气剂?等等

  • 我想我得到了我的答案“不要使用条件逻辑的选项”,我会坚持使用 if/else 并尝试重构逻辑以在将来减少它们。谢谢利诺(仍然没有对我的问题投反对票)。 (2认同)

Joo*_*gen 5

还有第三种形式(允许有些变化)。

return Stream.<Supplier<Object>>of(message::getA, message::getB, message::getC)
        .map(Supplier::get)
        .filter(Objects::nonNull)
        .findFirst()
        .orElse(null);
Run Code Online (Sandbox Code Playgroud)

目前可能是最不灵活和效率最高的,但是很清楚。

  • 您必须编写`Stream。&lt;Supplier &lt;Object &gt;&gt; of(...)`进行编译。 (3认同)
  • 我注意到在流中使用供应商使得这个评估和问题中一样懒惰:只有在 `getA` 返回 `null` 等情况下才会调用 `getB`。 (2认同)

Bas*_*que 5

tl;博士

如果您的目标是精简代码,则使用三元链接。性能可能与一系列 if-then-else 语句的性能相同。

        ( this.getA() != null ) ? this.getA()
                : ( this.getB() != null ) ? this.getB()
                : ( this.getC() != null ) ? this.getC()
                : null;
Run Code Online (Sandbox Code Playgroud)

三元链

正如Lino答案正确指出的那样,您正试图Optional超越其最初的设计目的(在 lambdas 和流中返回值)。通常最好Optional仅与return语句一起使用,并且仅当您要明确 null 是要返回的有效值时才使用。请参阅Brian Goetz 的这个答案

三元运算符是一个冷凝if-then-else,组合成一衬垫。

result = test ? valueToUseIfTestIsTrue : valueToUseIfTestIsFalse
Run Code Online (Sandbox Code Playgroud)

例子:

Color color = isPrinterMonochrome ? Color.GREY : Color.GREEN ; 
Run Code Online (Sandbox Code Playgroud)

使用三元语句链。

所以这:

    if ( this.getA() != null )
        return this.getA();
    else if ( this.getB() != null )
        return this.getB();
    else if ( this.getC() != null )
        return this.getC();
    else return null;
Run Code Online (Sandbox Code Playgroud)

……变成这样:

    return
            ( this.getA() != null ) ? this.getA()
                    : ( this.getB() != null ) ? this.getB()
                    : ( this.getC() != null ) ? this.getC()
                    : null;
Run Code Online (Sandbox Code Playgroud)

示例代码。

public String getA ()
{
    // return "A";
    return null;
}

public String getB ()
{
    // return "B";
    return null;
}

public String getC ()
{
    return "C";
    // return null;
}

public String getABC ()
{
    if ( this.getA() != null )
        return this.getA();
    else if ( this.getB() != null )
        return this.getB();
    else if ( this.getC() != null )
        return this.getC();
    else return null;
}

public String getABCTernary ()
{
    return
            ( this.getA() != null ) ? this.getA()
                    : ( this.getB() != null ) ? this.getB()
                    : ( this.getC() != null ) ? this.getC()
                    : null;
}
Run Code Online (Sandbox Code Playgroud)

运行该示例代码。

String s = this.getABCTernary();
System.out.println( "s: " + s );
Run Code Online (Sandbox Code Playgroud)

C

利弊

  • 三元链的好处是压缩代码,折叠成单行代码。
  • 缺点是您在这种特殊情况下两次调用 getter 方法只是为了获得一个值。对于简单的 fetch-the-variable 类型的 getter 来说不是问题,但如果 getter 是一种耗时的方法,例如远程 Web 服务调用,则会影响性能。而且,级联 if-then-else 也有同样的问题,也会调用你的 getter 两次。

表现

这两者在性能方面的比较

Java 中的三元运算符是"short-circuiting",这意味着与测试结果匹配的左侧或右侧是唯一调用的代码。在我们这里的代码中,如果getA返回非空值,则立即返回该值。对getB和的进一步调用getC永远不会执行。所以在这方面,链式三元的表现和级联 if-then-else 语句是一样的:first-match wins,不再调用。

如果您的意思是执行纳秒级的性能,我不知道。担心会落入过早优化的陷阱。现代 JVM 非常适合优化代码。


Joh*_*ohn 5

在我看来,经过大约20年的商业经验,我已经形成了一个观点:追求可读性是绝对愚蠢的,同时,故意编写复杂的代码是邪恶的。

我知道这完全违背了大众的观点。

然而,每个人都需要认识到这一点……

  1. 一个人可读的内容不一定对另一个人可读。即使在这个线程中,我们对于是否更具可读性也有不同的if看法Optional。无论我们所处的结构或情况如何,此类辩论都会发生。
  2. 如果我们每次都选择函数if式方法性能更高的选项,那么阅读该代码的人就会习惯它并发现它更具可读性- 因为这是他们现在已经习惯的风格。
  3. 高性能代码不一定“难以阅读”...但这又回到了第 1 点和第 2 点。开发人员需要真正了解他们所使用的语言的基础知识,并编写适合该语言的代码,而不是试图在他们的代码中形成“英语句子”。

所以,本质上:使用if...不要使用Optional