2015-11-06 158 views
0

我知道这很简单,但我无法找到任何问题。检查java上的列表是否为空会影响性能?

当我检查一个列表是否为空然后迭代它时,它会如何影响性能?

我有以下代码,我不知道第二次调用getContainers()是否再次执行该方法,或者编译器正在保存列表,因此不必再次运行getContainers()。

if (getContainers() != null) 
{ 
    for (Container container : getContainers()) 
{... 

如果这不是真的我正在考虑做类似下面的代码,但它似乎天真。

List<Container> listC = getContainers(); 
if (listC != null) 
{ 
    for (Container container : listC) 
{... 
+1

第二种方法调用getContainers一次,所以它的性能更好 –

+1

添加简单的System.out.println()到getContainers(),你会看到结果=)对我来说第二个变体更好。 – Lugaru

+0

检查一个对象是否为null几乎没有影响性能。第二种方法会有更好的性能,因为它不会重复'getContainers()'方法中完成的操作;换句话说,它得到(或者在'null'结果的情况下没有得到)列表***一次***;但这与'null'检查本身的性能影响无关。 – XenoRo

回答

0

这个问题令人混淆。事实是,您需要检查getContainers()是否在某个时候返回null,除非您允许NullPointerException,在这种情况下,您决定不抓住机会。在这两个示例中,您都检查为空,所以此操作完全相同。

你真正感兴趣的是,写两次getContainers()是否会影响性能。如果你明白这个方法除了返回一个存储在(可能是私有的)本地类中的对象之外没有任何其他的作用,那么你不应该担心任何性能,因为它会不明显。如果它确实做了更复杂的事情,但可以通过其他方法缓存,那么您应该查看其他方法。调用它两次可能不是这个方法的错误。如果有疑问,第二个例子保证它只被调用一次,代价是为它声明一个变量。

同样重要的是要注意的是,在增强的for循环,

for (Container container : getContainers()) 

的getContainers()只调用一次,并循环不是在每次迭代。它在内部检索列表并从中获取一个迭代器,该迭代器为每次迭代的容器赋值。唯一的问题是它不检查NPE。

4

第2版是非常有两个原因:

  • 不那么重要:你提到的,如果它不是由编译器自动
  • 更重要的是优化为性能优势:如果在多线程环境下运行时,对getContainers()的两次调用可能不会产生相同的结果:第一个调用可能不为空,但第二个调用可能不是。
+0

请注意,第二点中提到的可能性将禁止第一点中提到的编译器进行优化。 – skyking

+0

@skyking:不一定。我对Java编译器知之甚少,但我确实知道其他编译器根据多线程的缺失或存在情况进行不同的优化。我想到的是将来使用为单线程环境创建的代码可能很难找到错误。 –

+0

好的,但Java编译器是否真的可以确定在编译时?我的意思是,如果它将它编译为'.class'文件,然后'.class'文件与其他一些实际启动新线程的'.class'文件一起使用,那么如果第一个文件假定第二个文件应该不创建线程。 – skyking

2

它很可能会调用getContainers函数两次。除非知道它不能被覆盖,因此可以得出结论,它没有副作用并返回相同的值。

因此,这是合理的做你的第二个例子显示。但是请注意,它只会被调用两次,通常不会有足够的理由来尝试这种优化。

在尝试优化之前,应该实际测量代码在优化之前和之后需要多少时间。之前,因为它会告诉你是否需要优化,以及之后为了看到你已经实际优化了(我见过一些“优化”增加了执行时间)。

+1

由于你的答案是关于微优化的,所以你可能需要包含[this](http://stackoverflow.com/questions/1923795/java-method-invocation-vs-using-a-variable)链接:) – sam