![](/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.