相等测试顺序是否会影响Java的性能?

时间:2012-03-15 21:28:09

标签: java performance

我经常发现自己编写的代码如下:

private List<Foo> fooList = new ArrayList<Foo>();

public Foo findFoo(FooAttr attr) {
    for(Foo foo : fooList) {
        if (foo.getAttr().equals(attr)) {
            return foo;
        }
    }
}

但是,假设我正确防范空输入,我也可以像这样表达循环:

for(Foo foo : fooList) {
    if (attr.equals(foo.getAttr()) {
        return foo;
    }
}

我想知道上述形式之一是否具有相对于其他形式的性能优势。我很清楚过早优化的危险,但在这种情况下,我认为代码在任何一种方式都同样清晰,所以我正在寻找一种理由来选择一种形式而不是另一种形式,所以我可以建立我的编码习惯赞成这种形式。我认为,如果列表足够大,即使是小的性能优势也可能需要相当长的时间。

特别是,我想知道第二种形式是否可能更高效,因为equals()方法在同一对象上重复调用,而不是不同的对象?也许分支预测是一个因素?

6 个答案:

答案 0 :(得分:4)

我会在这里提供两条建议:

  1. 测量它
  2. 如果没有别的东西指向你的任何指示方向,那么当你大声说出来(或在你脑海里!)时,更喜欢最有意义且最自然的形式。

答案 1 :(得分:2)

我认为考虑分支预测会担心效率太低。但是,我发现代码的第二个示例更具可读性,因为您首先放置了一致对象。同样,如果您将this与其他对象that进行比较,我会将this放在第一位。

当然,equals是由程序员定义的,所以它可能是不对称的。你应该等于equivalence relation所以不应该这样。即使你有等价关系,订单也很重要。假设attr是各种foo.getAttr的超类,并且equals方法的第一个测试检查另一个对象是否是同一个类的实例。然后attr.equals(foo.getAttr())将通过第一次检查,但foo.getAttr().equals(attr)将无法通过第一次检查。

然而,担心这个级别的效率很少有好处。

答案 2 :(得分:2)

这取决于equals方法的实现。在这种情况下,我假设两个对象都是同一个类的实例。这意味着方法是平等的。这使没有性能差异

答案 3 :(得分:1)

如果两个对象的类型相同,那么它们应该执行相同的操作。如果没有,那么你事先不能确切知道会发生什么,但通常会很快停止(使用instanceof或其他东西)。

对于我自己,我通常在对给定参数进行非空检查的情况下启动该方法,然后使用attr.equals(foo.getAttr()),因为我不必在循环中检查null。我想是一个偏好问题。

答案 4 :(得分:1)

唯一影响性能的是不做任何事情的代码。

在某些情况下,您的代码大致相同,或者差异太小,无关紧要。这就是这种情况。

当交换.equals()时,它是有用的,当你有一个已知的值不能是null(这似乎不是这里的情况)你所使用的类型是已知的

e.g。

Object o = (Integer) 123;
String s = "Hello";

o.equals(s); // the type of equals is unknown and a virtual table look might be required
s.equals(o); // the type of equals is known and the class is final.

差别很小,我不担心。

  

DEVENTER(n)一个非常难以做出的决定,因为它很少取决于它,例如在公园里走动的方式

     

- 道格拉斯亚当斯和约翰劳埃德对Liff的更深层含义。

答案 5 :(得分:0)

性能应该是相同的,但就安全性而言,通常最好让左操作数是你确定不为null的东西,并让你的equals方法处理空值。

以例如:

String s1 = null;
s1.equals("abc");
"abc".equals(s1);

对equals的两次调用不等同,因为会发出NullPointerException(第一次),另一次会返回false。

出于这个原因,后一种形式通常优先用于与字符串常量进行比较。