I need to figure out the number of elements in an Iterable
in Java.
I know I can do this:
Iterable values = ...
it = values.iterator();
while (it.hasNext()) {
it.next();
sum++;
}
I could also do something like this, because I do not need the objects in the Iterable any further:
it = values.iterator();
while (it.hasNext()) {
it.remove();
sum++;
}
A small scale benchmark did not show much performance difference, any comments or other ideas for this problem?
The Iterable interface was introduced in JDK 1.5. It belongs to java. lang package. In general, an object Implementing Iterable allows it to be iterated. An iterable interface allows an object to be the target of enhanced for loop(for-each loop).
Iterator is an interface, which has implementation for iterate over elements. Iterable is an interface which provides Iterator.
An Iterable is basically an object that any user can iterate over. An Iterator is also an object that helps a user in iterating over another object (that is iterable). We can generate an iterator when we pass the object to the iter() method.
TL;DR: Use the utility method Iterables.size(Iterable)
of the great Guava library.
Of your two code snippets, you should use the first one, because the second one will remove all elements from values
, so it is empty afterwards. Changing a data structure for a simple query like its size is very unexpected.
For performance, this depends on your data structure. If it is for example in fact an ArrayList
, removing elements from the beginning (what your second method is doing) is very slow (calculating the size becomes O(n*n) instead of O(n) as it should be).
In general, if there is the chance that values
is actually a Collection
and not only an Iterable
, check this and call size()
in case:
if (values instanceof Collection<?>) {
return ((Collection<?>)values).size();
}
// use Iterator here...
The call to size()
will usually be much faster than counting the number of elements, and this trick is exactly what Iterables.size(Iterable)
of Guava does for you.
If you are working with java 8 you may use:
Iterable values = ...
long size = values.spliterator().getExactSizeIfKnown();
it will only work if the iterable source has a determined size. Most Spliterators for Collections will, but you may have issues if it comes from a HashSet
or ResultSet
for instance.
You can check the javadoc here.
If Java 8 is not an option, or if you don't know where the iterable comes from, you can use the same approach as guava:
if (iterable instanceof Collection) {
return ((Collection<?>) iterable).size();
} else {
int count = 0;
Iterator iterator = iterable.iterator();
while(iterator.hasNext()) {
iterator.next();
count++;
}
return count;
}
This is perhaps a bit late, but may help someone. I come across similar issue with Iterable
in my codebase and solution was to use for each
without explicitly calling values.iterator();
.
int size = 0;
for(T value : values) {
size++;
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With