为什么在 Java 中 list.size()>0 比 list.isEmpty() 慢?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/1508975/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Why is list.size()>0 slower than list.isEmpty() in Java?
提问by Ashish Agarwal
Why is list.size()>0
slower than list.isEmpty()
in Java? On other words why isEmpty()
is preferable over size()>0
?
为什么list.size()>0
比list.isEmpty()
Java慢?换句话说,为什么比isEmpty()
更可取size()>0
?
When I look at the implementation in ArrayList
, then it looks like the speed should be the same:
当我查看 中的实现时ArrayList
,看起来速度应该是一样的:
ArrayList.size()
ArrayList.size()
/**
* Returns the number of elements in this list.
*
* @return the number of elements in this list
*/
public int size() {
return size;
}
ArrayList.isEmpty()
ArrayList.isEmpty()
/**
* Returns <tt>true</tt> if this list contains no elements.
*
* @return <tt>true</tt> if this list contains no elements
*/
public boolean isEmpty() {
return size == 0;
}
If we just write a simple program to get the time take by both the methods, that case size()
will take more isEmpty()
in all cases, why this so?
如果我们只是编写一个简单的程序来获取这两种方法所花费的时间,那么在所有情况下size()
都会花费更多的isEmpty()
时间,为什么会这样?
Here is my TestCode;
这是我的测试代码;
import java.util.List;
import java.util.Vector;
public class Main {
public static void main(String[] args) {
List l=new Vector();
int i=0;
for(i=0;i<10000;i++){
l.add(new Integer(i).toString());
}
System.out.println(i);
Long sTime=System.nanoTime();
l.size();
Long eTime=System.nanoTime();
l.isEmpty();
Long eeTime=System.nanoTime();
System.out.println(eTime-sTime);
System.out.println(eeTime-eTime);
}
}
Here eTime-sTime>eeTime-eTime
in all cases. Why?
eTime-sTime>eeTime-eTime
在所有情况下都在这里。为什么?
采纳答案by JRL
Your testing code is flawed.
你的测试代码有缺陷。
Just reverse the order, i.e call isEmpty first and size > 0 second and you'll get the oppositeresult. This is due to class loading, caching, etc.
只需颠倒顺序,即首先调用 isEmpty 并且 size > 0 秒,您将得到相反的结果。这是由于类加载、缓存等原因。
回答by Stephen Denne
Counting items in a linked list can be very slow.
计算链表中的项目可能非常慢。
回答by Andrzej Doyle
For ArrayList
, yes — you are correct that the operations take (roughly) the same time.
对于ArrayList
,是的 - 您是正确的,操作花费(大致)相同的时间。
For other implementations of List
— for?example, a na?ve linked?list* — counting the size might take a very long time, while you only actually care whether it is greater than zero.
对于其他实现List
——例如,一个简单的链接列表*——计算大小可能需要很长时间,而你实际上只关心它是否大于零。
So if you absolutely know that the list is an implementation of ArrayList
and will never ever change, then it does not really matter; but:
因此,如果您绝对知道该列表是 的实现ArrayList
并且永远不会改变,那么这并不重要;但:
- This is bad programming practice to tie yourself down to a specific implementation.
- If things change a few years down the line with code restructuring, testing will show that "it?works," but things are running less efficiently than before.
- Even in the best case,
size() == 0
is still not fasterthanisEmpty()
, so there is no compelling reason to ever use the former. isEmpty()
is a clearer definition of what it is you actually care about and are testing, and so makes your code a bit more easily understandable.
- 这是将自己束缚在特定实现上的糟糕编程实践。
- 如果事情随着代码重组几年后发生变化,测试将表明“它?有效”,但事情的运行效率比以前低。
- 即使在最好的情况下,
size() == 0
仍然不比快isEmpty()
,因此没有令人信服的理由使用前者。 isEmpty()
是对您真正关心和正在测试的内容的更清晰定义,因此使您的代码更易于理解。
* I originally wrote LinkedList here, implicitly referencing java.util.LinkedList
, though that particular implementation does store its size explicitly, making size()
an O(1) operation here. A na?ve linked?list operation might not do this, and in the more general sense there is no efficiency guarantee on implementations of List
.
* 我最初在这里编写了 LinkedList ,隐式引用java.util.LinkedList
,尽管该特定实现确实显式存储其大小,size()
在此处进行 O(1) 操作。一个简单的链表操作可能不会这样做,而且在更一般的意义上, 的实现没有效率保证List
。
回答by Joachim Sauer
Given those two implementations, the speed should be the same, that much is true.
鉴于这两种实现,速度应该是相同的,这是真的。
But those are by far not the only possible implementations for these methods. A primitive linked list (one that doesn't store the size separately) for example could answer isEmpty()
much faster than a size()
call.
但到目前为止,这些并不是这些方法的唯一可能实现。例如,原始链表(不单独存储大小的链表)可以isEmpty()
比size()
呼叫快得多。
More importantly: isEmpty()
describes your intent exactly, while size()==0
is unnecessarily complex (not hugely complex of course, but any unnecessary complexity at all should be avoided).
更重要的是:isEmpty()
准确地描述你的意图,而size()==0
不必要的复杂(当然不是非常复杂,但应该避免任何不必要的复杂性)。
回答by wds
You said:
你说:
Here
eTime-sTime>eeTime-eTime
in all cases Why?
这里
eTime-sTime>eeTime-eTime
在所有情况下为什么?
First off, it's probably because of your testing code. You can't test the speed of calling l.size() and l.isEmpty() at the same time, since they both query the same value. Most likely calling l.size() has loaded the size of your list into your cpu cache and calling l.isEmpty() is a lot faster as a result.
首先,这可能是因为您的测试代码。您无法测试同时调用 l.size() 和 l.isEmpty() 的速度,因为它们都查询相同的值。很可能调用 l.size() 已将列表的大小加载到 cpu 缓存中,因此调用 l.isEmpty() 会快很多。
You could try calling l.size() a couple of million times and l.isEmpty() a couple of million times in two separate programsbut in theory the compiler could just optimize away all those calls since you're not actually doing anything with the results.
你可以尝试在两个单独的程序中调用 l.size() 几百万次和 l.isEmpty() 几百万次,但理论上编译器可以优化掉所有这些调用,因为你实际上没有做任何事情结果。
In any case, the performance difference between the two will be negligible, especially once you do the comparison you need to do to see if the list is empty (l.size() == 0
). Most likely the generated code will look almost completely similar. As some other posters noted, you want to optimize for readability in this case, not speed.
在任何情况下,两者之间的性能差异都可以忽略不计,尤其是在进行比较后,您需要查看列表是否为空 ( l.size() == 0
)。很可能生成的代码看起来几乎完全相似。正如其他一些海报指出的那样,在这种情况下,您希望优化可读性,而不是速度。
edit: I tested it myself. It's pretty much a toss-up. size()
and isEmpty()
used on Vector
gave differing results on long runs, neither beat the other consistently. When run on an ArrayList
size()
seemed faster, but not by much. This is most likely due to the fact that access to Vector
is synchronized, so what you're really seeing when trying to benchmark access to these methods is synchronisation overhead, which can be very sensitive.
编辑:我自己测试过。这几乎是一个折腾。size()
并且isEmpty()
使用 onVector
在长跑中给出了不同的结果,两者都没有始终如一地击败对方。运行时ArrayList
size()
似乎更快,但速度并不快。这很可能是因为访问Vector
是同步的,因此在尝试对这些方法的访问进行基准测试时,您真正看到的是同步开销,这可能非常敏感。
The thing to take away here is that when you're trying to optimize a method call with a couple nanoseconds difference in execution time, then you're doing it wrong. Get the basics right first, like using Long
s where you should be using long
.
这里要解决的问题是,当您尝试优化具有几纳秒执行时间差异的方法调用时,您就做错了。首先获得基础知识,例如Long
在应该使用s 的地方使用s long
。
回答by Robert Munteanu
I'm sorry, but your benchmark is flawed. Take a look at Java theory and practice: Anatomy of a flawed microbenchmarkfor a general description on how to approach benchmarks.
我很抱歉,但你的基准是有缺陷的。看一看Java 理论和实践:有缺陷的微基准的剖析,了解如何接近基准的一般描述。
Update: for a proper benchmark you should look into Japex.
更新:对于适当的基准测试,您应该查看Japex。
回答by Jesper
It is impossible to say in general which is faster, because it depends on which implementation of interface List
you are using.
一般不可能说哪个更快,因为这取决于List
您使用的接口实现。
Suppose we're talking about ArrayList
. Lookup the source code of ArrayList
, you can find it in the file src.zipin your JDK installation directory. The source code of the methods isEmpty
and size
looks as follows (Sun JDK 1.6 update 16 for Windows):
假设我们在谈论ArrayList
. 查找源代码ArrayList
,可以在JDK安装目录的src.zip文件中找到。方法isEmpty
和size
外观的源代码如下(Sun JDK 1.6 update 16 for Windows):
public boolean isEmpty() {
return size == 0;
}
public int size() {
return size;
}
You can easily see that both expressions isEmpty()
and size() == 0
will come down to exactly the same statements, so one is certainly not faster than the other.
您可以很容易地看到这两个表达式isEmpty()
和size() == 0
将归结为完全相同的语句,因此一个肯定不会比另一个更快。
If you're interested in how it works for other implementations of interface List
, look up the source code yourself and find out.
如果您对它如何用于 interface 的其他实现感兴趣List
,请自行查找源代码并找出答案。
回答by Priyabrata Hota
According to PMD ( static ruleset based Java source code analyzer ) isEmpty() is preferred. You can find the PMD ruleset here. Search for "UseCollectionIsEmpty" rule.
根据 PMD(基于静态规则集的 Java 源代码分析器),首选 isEmpty()。您可以在此处找到 PMD 规则集。搜索“UseCollectionIsEmpty”规则。
http://pmd.sourceforge.net/rules/design.html
http://pmd.sourceforge.net/rules/design.html
According to me it also helps in keeping the entire source code consistent rather than half of the folks using isEmpty() and the rest using size()==0.
据我说,它也有助于保持整个源代码的一致性,而不是一半的人使用 isEmpty() 而其余的人使用 size()==0。
回答by sicotron
.size() has to look at the entire list, while .isEmpty() can stop at the first one.
.size() 必须查看整个列表,而 .isEmpty() 可以在第一个停止。
Obviously implementation dependent, but as has been said before, if you don't need to know the actual size, why bother counting all the elements?
显然依赖于实现,但如前所述,如果您不需要知道实际大小,为什么还要计算所有元素?