2

我读过一些 JVM 可以通过删除边界检查来优化代码执行。我想弄清楚的是哪种编码技术会更好。

在下面的方法example1中,JVM 是否会弄清楚并消除对source[index]引用的边界检查?

example2是更好的代码实践吗?看起来是这样,但在循环内的某些算法中,索引超出范围是正常情况。因此,您不想在该循环内生成大量 Exception 对象。

public void example1(int [] source, int index) {
    if (index >= 0 && index < source.length)
        System.out.println("Value is " + source[index]);
    else 
        System.out.println("Out of range: " + index);
}

public void example2(int [] source, int index) {
    try {        
        System.out.println("Value is " + source[index]);        
    } catch (IndexOutOfBoundsException exp) {
        System.out.println("Out of range: " + index);
    }
}

这些代码片段仅具有代表性。我知道在这些示例中,边界检查对性能几乎没有影响。但是,我正在开发一个嵌入式协议应用程序,其中冗余边界检查将加起来。

4

2 回答 2

5

对于您的第一个问题,在 example1 中,理论上可以消除边界检查。我希望最好的现代 JIT 编译器能够做到这一点(例如,当 source[index] 扩展时,可能通过边界检查中的公共子表达式消除)。像往常一样,这将取决于实现,因此您不能依赖它。OTOH,即使没有消除边界检查,差异也将是微不足道的 - 您正在为 source.length 访问已经缓存的内存位置并进行几个整数比较,因此开销很小。

example2 不是一个好习惯——你遇到了一个异常,但随后捕捉到它并继续,就好像什么都没发生一样。除非您密切关注标准输出,否则您可能会完全忽略代码中存在错误的事实。

根据您认为“索引”的有效输入,基本上有两种常见的“好”可能性:

  1. 超出范围的索引值是预期的,并且被视为有效输入。在这种情况下,您应该像示例 1 中那样明确地测试和处理它。在这种情况下,您不需要抛出任何类型的异常。

  2. 超出范围的索引是意外的(因此是调用代码中的错误)。您的代码应在此处引发异常。如果您愿意,您可以使用自己的消息捕获并重新抛出异常,但您也可以让 IndexOutOfBounds 异常传播。不要担心这种异常处理对性能的影响——您刚刚发现了一个错误,因此您希望程序尽可能快地“大声”失败......

于 2011-07-03T16:25:10.617 回答
1

I don't see how the index being out of bounds could ever be a normal condition. Either your algorithm has a bug, or you don't validate input correctly. And validating input, in this case, consists in checking that the index is in the bounds. Checking it with an if (as in your first snippet) is obviously much more readable, clean and efficient than catching an exception.

于 2011-07-03T16:26:36.607 回答