我经常发现自己编写的代码如下:
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()
方法在同一对象上重复调用,而不是不同的对象?也许分支预测是一个因素?
答案 0 :(得分:4)
我会在这里提供两条建议:
答案 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。
出于这个原因,后一种形式通常优先用于与字符串常量进行比较。