![](/img/trans.png)
[英]Why is list.size()>0 slower than list.isEmpty() in Java?
[英]Is !list.isEmpty() and list.size()>0 equal?
我已经看到如下代码:
if (!substanceList.isEmpty() && (substanceList.size() > 0))
{
substanceText = createAmountText(substanceList);
}
以下是有效的重构吗?
if (!substanceList.isEmpty())
{
substanceText = createAmountText(substanceList);
}
不胜感激对上述代码的解释以及第二个版本是否可能导致错误?
如果有疑问,请阅读 Javadoc:
如果此集合不包含任何元素,则返回 true。
返回此集合中的元素数
因此,假设正确实现了集合:
collection.isEmpty() <=> collection.size() == 0
或者,相反:
!collection.isEmpty() <=> collection.size() != 0
由于元素的数量应该只为正数,这意味着:
!collection.isEmpty() <=> collection.size() > 0
所以是的,这两种形式是等价的。
警告:实际上,只有当您的集合没有同时被另一个线程修改时,它们才等效。
这个:
!substanceList.isEmpty() && (substanceList.size() > 0)
根据我上面提出的逻辑,相当于:
!substanceList.isEmpty() && !substanceList.isEmpty()
您只能将其简化为
!substanceList.isEmpty()
如果你能保证它的值在substanceList.isEmpty()
评估之间不会改变。
实际上,您不太可能需要关心这些情况之间的区别,至少在代码的这一点上是这样。 您可能需要关心在另一个线程中更改的列表,但是,如果它在执行createAmountText
之前(或同时)变为空。 但这不是这次重构引入的东西。
TL;DR:使用if (!substanceList.isEmpty()) {
几乎做同样的事情,并且更清晰易读。
实际上,您可以阅读JDK中下载的源代码:
/**
* 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;
}
我认为这可以解决所有疑问。
第一种方法和第二种方法之间的唯一区别是第一种方法执行冗余检查。 没有别的。
因此,您宁愿避免冗余检查并采用第二种方法。
AbstractCollection
中isEmpty()
实现如下:
public boolean isEmpty() {
return size() == 0;
}
所以你可以放心地假设!list.isEmpty()
等价于list.size() > 0
。
至于“什么是更好的代码”,如果要检查列表是否为空, isEmpty()
肯定更具表现力。
子类也可能覆盖AbstractCollection
isEmpty()
并以比size() == 0
更有效的方式实现。 所以(纯粹理论上) isEmpty()
可能更有效。
是的,它可以像您一样重构。 这两种方法的问题在于,每次要调用 List 上的createAmountText
方法时,都需要进行检查。 这意味着您将重复逻辑,更好的方法是使用 DRY(不要重复自己)原则并将这些检查因素纳入您的方法。 所以你的方法的主体应该被这个检查封装。
它应该看起来像:
<access modifier> String createAmountText(List substanceList){
if(substanceList != null && !substanceList.isEmpty()){
<The methods logic>
}
return null;
}
Collection.size()
和Collection.isEmpty()
的javadocs说:
boolean isEmpty()
如果此集合不包含任何元素,则返回 true。
int size()
返回此集合中的元素数
由于“不包含任何元素”意味着集合中的元素数量为零,因此list.isEmpty()
和list.size() == 0
将评估为相同的值。
我想对上面的代码做一些解释
第二个版本是正确的。 第一个版本看起来像是由自动代码生成器或并不真正了解 Java 的程序员编写的。 没有充分的理由以这种方式编写代码。
(注意:如果其他线程可以并发修改列表,那么除非有适当的同步,否则两个版本都有问题。如果列表操作不同步则可能是内存危害。但在第一个版本中,也有可能竞争条件......列表显示为空且大小非零!)
并想知道第二种方式可能会导致一些错误。
不会。
顺便说一下,由于以下几个原因, list.isEmpty()
比list.size() == 0
更可取:
O(N)
操作,也可能是其他不良影响。 例如,如果一个集合是一个惰性列表,它只会在您迭代元素时被具体化,那么调用size()
可能会导致过多的内存使用。当然 - 这两种方法可以用来表达同样的事情。
但值得在这里补充:选择size() > 0
在某种程度上更直接违反了Tell, don't ask原则:您访问“实现细节”,然后基于此做出决定。
从这个意义上说, isEmpty()
应该是你的首选!
当然,您在使用isEmpty()
时仍然违反了 TDA - 因为您再次从某个对象获取状态然后对其做出决定。
因此,真正最好的选择是编写完全不需要对集合的内部状态进行此类查询的代码,然后驱动对它的决策。 相反,只需确保createAmountText()
正确处理您传入的空列表! 为什么这个列表,或该方法需要用户关心的列表是否为空?
长话短说:也许这里是“过度思考”——但同样:不使用这些方法会导致你编写更少的代码! 这总是一个好主意的迹象。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.