Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is it useful to check if a Java collection is empty before beginning iteration?

In the two styles below, an Iterator object is allocated. Is it useful to check if the collection is empty before iterating? I don't know if this qualifies as "premature optimization". Hopefully, someone with deep knowledge of JVM garbage collectors can provide insight.

Also, I don't know how the Java compiler handles for-each loops. I assume style B is converted to style A automatically. But... maybe an empty check is included.

Loop Style A

Collection<String> collection = ...
Iterator<String> iter = collection.iterator();
while (iter.hasNext()) {
    String value = iter.next();
    // do stuff
    // maybe call iter.remove()
}

Loop Style B

Collection<String> collection = ...
for (String value : collection) {
    // do stuff
}

Loop Style A (Modified)

Collection<String> collection = ...
if (!collection.isEmpty()) {
    Iterator<String> iter = collection.iterator();
    while (iter.hasNext()) {
        String value = iter.next();
        // do stuff
        // maybe call iter.remove()
    }
}

Loop Style B (Modified)

Collection<String> collection = ...
if (!collection.isEmpty()) {
    for (String value : collection) {
        // do stuff
    }
}
like image 316
kevinarpe Avatar asked Oct 15 '14 04:10

kevinarpe


People also ask

What happens to for loop if list is empty?

If the list is empty, the for-each cycle is not executed even once.

Which collection is best for iteration in Java?

There are three common ways to iterate through a Collection in Java using either while(), for() or for-each(). While each technique will produce more or less the same results, the for-each construct is the most elegant and easy to read and write.

Does Java collection isEmpty check for NULL?

If you use the Apache Commons Collections library in your project, you may use the CollectionUtils. isEmpty and MapUtils. isEmpty() methods which respectively check if a collection or a map is empty or null (i.e. they are "null-safe").

Does forEach work on empty list?

Using the items parameterWhen items is null or an empty list, a! forEach() returns an empty list of the same type as items. It does not evaluate the expression in these cases.


2 Answers

Yes, this is pretty definitely going to be a premature optimization, if it can ever help. Your loop would have to be extremely performance critical, and usually called with empty collections, and for some reason unable to optimize away most of the cost of creating an actual iterator object.

In that perfect storm, this massive source ugliness could possibly be justified. But more likely you could rearrange something to help the compiler optimize better, like keeping your iterator local.


The iterator object is (usually?) function-local and therefore cheap to create (could just live in registers, no heap allocation needed). See https://www.beyondjava.net/escape-analysis-java for some details about how JVMs do "scalar replacement" on an Object if escape analysis proves that it's purely local, no references to it are visible to other code. So the possible savings don't even include a memory allocation.

If this did JIT-compile to a separate check before doing something, it's extra instructions that always run even when the collection is not empty.

Optimize for the most common case. Instead of adding extra code to slightly speed up the rare empty case, leave it out to speed up the common non-empty case.

I think most loops tend to run on non-empty collections. Small is common for some cases, but empty is usually rare. Perhaps you have a loop that often or usually runs on empty collections, e.g. a rarely-used feature in a program. Then it's worth thinking about optimizing for that case. (Whether this is a useful way to go about it is another matter)

This extra call to collection.isEmpty() might just optimize into the loop condition anyway, if it JIT-compiles to a simple pointer-increment loop over an array, with a start and end pointer both kept in registers. That's the best case, but then the extra source noise is useless and what you would have gotten anyway.


You could argue that if for (String value : collection) doesn't already compile to the most efficient way to loop over a collection, that's the compiler + JVM's fault, and you shouldn't have to make your source ugly for it. That's probably true to a point, although introducing a call to .isEmpty() isn't something a compiler or runtime can do unless they can inline that method to see that it's really checking the same thing an iterator would. But with JIT compilation, everything is available to be inlined.


TL:DR: It's likely that a good JIT compiler doesn't really spend any real work creating an iterator for most simple collections, and there's nothing to be saved.

In other cases, it's still probably better (for performance) not to do this unless your loop usually runs on empty collections, or (even more unlikely) iterator creation is somehow very expensive.

like image 84
Peter Cordes Avatar answered Oct 27 '22 00:10

Peter Cordes


No , you don't have to check for empty. The first iteration will do the trick for you.

like image 44
KingJulien Avatar answered Oct 26 '22 22:10

KingJulien