简体   繁体   中英

Is !list.isEmpty() and list.size()>0 equal?

I've seen code as below:

     if (!substanceList.isEmpty() && (substanceList.size() > 0))
    {
      substanceText = createAmountText(substanceList);
    }

Would the following be a valid refactor?

     if (!substanceList.isEmpty())
    {
      substanceText = createAmountText(substanceList);
    }

I would be grateful for an explanation of the above code and whether the second version may cause errors?

If in doubt, read the Javadoc:

Collection.isEmpty() :

Returns true if this collection contains no elements.

Collection.size() :

Returns the number of elements in this collection

So, assuming the collection is implemented correctly:

collection.isEmpty() <=> collection.size() == 0

Or, conversely:

!collection.isEmpty() <=> collection.size() != 0

Since the number of elements should only be positive, this means that:

!collection.isEmpty() <=> collection.size() > 0

So yes, the two forms are equivalent.

Caveat : actually, they're only equivalent if your collection isn't being modified from another thread at the same time.

This:

!substanceList.isEmpty() && (substanceList.size() > 0)

is equivalent to, by the logic I present above:

!substanceList.isEmpty() && !substanceList.isEmpty()

You can only simplify this to

!substanceList.isEmpty()

if you can guarantee that its value doesn't change in between evaluations of substanceList.isEmpty() .

Practically, it is unlikely that you need to care about the difference between these cases, at least at this point in the code. You might need to care about the list being changed in another thread, however, if it can become empty before (or while) executing createAmountText . But that's not something that was introduced by this refactoring.

TL;DR: using if (!substanceList.isEmpty()) { does practically the same thing, and is clearer to read.

Actually, you can read the source code downloaded in the 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;
}

I think that this settles all the queries.

The only difference between the first and the second approach is that the first approach performs a redundant check. nothing else.

Thus, you'd rather avoid the redundant check and go with the second approach.

Implementation of isEmpty() in AbstractCollection is as follows:

public boolean isEmpty() {
    return size() == 0;
}

So you can safely assume that !list.isEmpty() is equivalent to list.size() > 0 .

As for "what is better code", if you want to check if the list is empty or not, isEmpty() is definitely more expressive.
Subclasses might also override isEmpty() from AbstractCollection and implement in more efficient manner than size() == 0 . So (purely theoretically) isEmpty() might be more efficient.

Yes, it can be refactored as you did. The issue with both approaches is that you would do the check every time you want to call the method createAmountText on a List. This means you would be repeating the logic, a better way would be to use DRY (don't Repeat Yourself) principle and factor these checks into your method. So your method's body should encapsulated by this check.

It should look like:

<access modifier> String createAmountText(List substanceList){
   if(substanceList != null && !substanceList.isEmpty()){
       <The methods logic>
   }
   return null;   
}

The javadocs for Collection.size() and Collection.isEmpty() say:

boolean isEmpty()

Returns true if this collection contains no elements.

int size()

Returns the number of elements in this collection

Since "contains no elements" implies that the number of elements in the collection is zero, it follows that list.isEmpty() and list.size() == 0 will evaluate to the same value.

I want to some explanation of above code

The second version is correct. The first version looks like it was written either by an automatic code generator, or a programmer who doesn't really understand Java. There is no good reason to write the code that way.

(Note: if some other thread could be concurrently modifying the list, then both versions are problematic unless there is proper synchronization. If the list operations are not synchronized then may be memory hazards. But in the first version, there is also the possibility of a race condition ... where the list appears be empty and have a non-zero size!)

and want to know second way may be caused some error.

It won't.


Incidentally list.isEmpty() is preferable to list.size() == 0 for a couple of reasons:

  • It is more concise (fewer characters).
  • It expresses the intent of your code more precisely.
  • It may be more efficient. Some collection implementations may need to count the elements in the collection to compute the size. That may be an O(N) operation, and could other undesirable effects. For example, if a collection is a lazy list that only gets reified as you iterate the elements, then calling size() may result in excessive memory use.

Sure - the two methods can be used to express the same thing.

But worth adding here: going for size() > 0 is somehow a more direct violation of the Tell, don't ask principle: you access an "implementation detail", to then make a decision based on that.

In that sense, isEmpty() should be your preferred choice here!

Of course, you are still violating TDA when using isEmpty() - because you are again fetching status from some object to then make a decision on it.

So the really best choice would be to write code that doesn't need at all to make such a query to internal state of your collection to then drive decisions on it. Instead, simply make sure that createAmountText() properly deals with you passing in an empty list! Why should users of this list, or of that method need to care whether the list is empty or not?!

Long story short: maybe that is "over thinking" here - but again: not using these methods would lead you to write less code! And that is always an indication of a good idea.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM