其中一个陈述是否有益处

时间:2014-05-17 00:06:40

标签: java optimization

这两个片段之间有什么区别吗?性能?可读性?否则?

if (arg > 0) {
    for (int i = 0; i < arg; i++) {
        sb.append(">");
    }
} else if (arg < 0) {
    for (int i = 0; i < Math.abs(arg); i++) {
        sb.append("<");
    }
}
for (int i = 0; i < Math.abs(arg); i++) {
    if (arg > 0) {
        sb.append(">");
    } else if (arg < 0) {
        sb.append("<");
    }
}

就个人而言,我更喜欢前者,因为它更清楚地表明arg是常数。

5 个答案:

答案 0 :(得分:3)

我说两者都很不可读。无论如何,关于速度:

  • 首先,测量是否应该优化此部分。大多数时候,答案是&#34; no&#34;。
  • 如果答案恰好是&#34;是&#34;:尝试不同的变体并衡量他们的表现。

好处是JIT喜欢简单易读的代码。

我只是为了

for (int i = 0; i < Math.abs(arg); i++) sb.append(arg > 0 ? ">" : "<");

并希望

  • JIT认识到arg是一个循环不变量
  • Math.abs(arg)只会评估一次
  • 所有arg > 0 ? ">" : "<"

如果我在优化后感到疯狂,我会写

char c = arg > 0 ? '>' : '<'; // char instead of String
for (int i = Math.abs(arg); i > 0; i--) sb.append(x);

但实际上有一个Guava解决方案:

sb.append(Strings.repeat(arg > 0 ? ">" : "<", Math.abs(arg));

答案 1 :(得分:2)

如果你说arg是一个常量,那么前者会更有效率,因为你只评估if / else条件一次,而不是每次循环迭代时都要评估它。但是,如果arg在每次循环迭代中都不是常量,那么你显然想要使用后者。

答案 2 :(得分:2)

我不会使用其中任何一个;我会尝试下面两个片段中的一个。


第一个变体

    char c = arg > 0 ? '>' : '<';

    int  n = Math.abs(arg);

    StringBuffer sb = new StringBuffer(n);

    for (int i = 0; i < n; ++i) {

        sb.append(c);
    }

在这里,我的建议是:

  • 首选对象的基元(char可能比String更快。)

  • 如果您已经知道尺寸(通过调用StringBuffer(int n)),请预先分配缓冲区。

  • 首选无分支循环(更好的可读性,维护性和速度)。


第二个变体

    char c = arg > 0 ? '>' : '<';

    int  n = Math.abs(arg);

    char[] content = new char[n];

    Arrays.fill(content, c);

    StringBuffer sb = new StringBuffer(n);

    sb.append(content);

在这里,我的建议是:

  • 首选算法自编循环(上面的代码片段根本没有循环)。

  • 特别是,System.arraycopy()(由sb.append(char[] )调用)是一种本机方法,不会在每次迭代中执行绑定检查。

我个人更喜欢这个第二版,因为它是无环路的。它的缺点是它分配和触摸与content对应的内存两次:首先填充content,然后将其复制到StringBuffer


最重要的是,对您的代码进行分析,以确保您没有premature optimization

“想要速度?测量。”Howard Hinnant

答案 3 :(得分:1)

如果arg小于0,则不会运行循环,因为i在开始时等于0,当然不小于0.

因此,如果arg小于0,则第二个选项会变慢,因为它会遍历所有选项,而不管它是否真实。

答案 4 :(得分:1)

我不喜欢他们中的任何一个:

  • 第一个,因为当您已经知道该标志时,无需致电Math.abs()
  • 第二个,因为如果arg为否定,它将不会终止。所以它在任何情况下都不等同于第一个。所以你要比较苹果和橘子。