2

An object implementing Iterable interface must have a method with this signature:

Iterator<T> iterator()

o being an Iterable, is this code safe?

while(o.iterator().hasNext()) { ... }

In other terms, may iterator() returns null in case there is nothing to iterate over?

EDIT:

1- As some of you point out, the iterator returned is different each time o.iterator() is executed. Fair enough! I must agree that I had forgotten this point when writing the question.

Let's say this line is rewritten:

Iterator<String> it = o.iterator();
....
....
while(it.hasNext() {...}

2- As some of you point out, this is bad programming practice to return null when the documentation for Iterable.iterator() says: "Returns an iterator over a set of elements of type T."

However my question is about whether returning null is prevented directly or indirectly by some 'contract' in the Java API documentation. To me "Returns an iterator over a set of elements of type T" doesn't prevent returning null. I may be wrong.

Conclusion from your answers and additional research

Overall: Java API has no mean to say if the iterator value may be null or not, unless by stating it explicitly in the documentation. In this case, nothing is stated, however good sense allows to think that a null iterator value will never be returned from Java API methods. This may be different for API written by individuals.

  • Nothing in the documentation prevents the returned value to be null (e.g. @NotNull)
  • In the Javadoc, many @Return are explicit when null is also to be anticipated
  • This question is about null return values in general, interesting.
  • I've found an attempt for a language to describe APIs, though it for .NET
Community
  • 1
  • 1
mins
  • 6,478
  • 12
  • 56
  • 75
  • 1
    Why are you calling `o.iterator()` in the loop? Just get it once and simply call `hasNext()` first. – Braj Jun 07 '14 at 12:15
  • 1
    [Not according to the docs](http://docs.oracle.com/javase/7/docs/api/java/lang/Iterable.html). (Obviously, that doesn't prevent someone from writing an implementation that *does* return `null`, but that would be a violation of the interface.) – Oliver Charlesworth Jun 07 '14 at 12:15
  • The doc says: Returns an iterator over a set of elements of type T. nothing about null excluded. – mins Jun 07 '14 at 12:16
  • 1
    @mins `null` is not an iterator over a set of elements. – Matt Ball Jun 07 '14 at 12:18
  • 1
    Nothing about a `null` *included* either. The JDK Javadoc is littered with @return tags that specify that `null` can be returned. If that isn't present in this case, you aren't entitled to assume it anyway. – user207421 Jun 07 '14 at 13:14

2 Answers2

5

may iterator() returns null in case there is nothing to iterate over?

null may be returned (there are no tools in Java to prevent you from doing that) but it never should be. Instead return Iterator which hasNext() method returns false.

You need to know that purpose of Iterable objects is to be used with for-each loop

for (Type item : IterableInstance){
    //handle 'item'
    System.out.println(item);
}

which is translated to something like

for(Iterator<Type> i = someList.iterator(); i.hasNext(); ) {
    Type item = i.next();

    //handle 'item'
    System.out.println(item);
}

So if iterator() returns null you will get NullPointerException at i.hasNext() (since i would hold null). To avoid NPE you need proper iterator instance which for hasNext() will return false (if there are no elements to iterate). This will prevent loop iterations.


Aside form that there is other problem in your code

while(o.iterator().hasNext()) { ... }

What you are doing here is that each time condition is checked new iterator is created because you are calling o.iterator() which will start to iterate from first element. In other words you are checking each time if first element exists, which can cause infinite loop if o is not empty.

What you need is

Iterator<SomeType> it = o.iterator();
while(it.hasNext()) { ... }
Pshemo
  • 122,468
  • 25
  • 185
  • 269
  • 1
    Thanks. That seems the complete answer. Regarding new instance of iterator each time it is evaluated: agreed, but let's say this line is rewritten: while(it.hasNext() {...}, where it has been assigned once. Can you please provide a reference for your statement? – mins Jun 07 '14 at 12:21
  • I am not sure what kind of reference you want to find. Pure logic seems to be enough to say that `null` should never be returned as result of `iterator()`. You need to know that `Iterable` objects are mainly used in `for-each` loop (`for(T element : IterableInstance)`). If you would implement `iterable()` would you want people who will use your code to also have to handle `NullPointerException` each time they use it in `for-each`? – Pshemo Jun 07 '14 at 12:26
  • @mins In other words, returning `null` is allowed (there is no mechanism to prevent it) but it is VERY BAD DESIGN and it shouldn't be used. Classes from Collection framework (`ArrayList`, `HashSet`, ..,) never returns `null` for instance. You can check it by looking at their source-code. – Pshemo Jun 07 '14 at 12:33
  • yes this is my point... what you say makes sense, but I can't find any 'contract' that say the returned iterator is not allowed to be null. null is not an invalid return value for a method which returns Iterator, right? – mins Jun 07 '14 at 12:35
1

In other terms, may iterator() returns null in case there is nothing to iterate over?

No. A correct implementation of the Iterable interface will never return null from its iterator() method. It will return a non-null Iterator whose hasNext() method immediately returns false.

However:

is this code safe?

Sure, but it doesn't do what you think it does, because the contract of iterator() is to return a different iterator every time iterator() is called.

Matt Ball
  • 354,903
  • 100
  • 647
  • 710
  • iterator() returns a different instance each time, ok. I've edited my question. Do you have some reference to back your answer about null not allowed? As far as I know null is a valid value for a return type Iterator? – mins Jun 07 '14 at 12:28
  • 1
    Yes, in one sense `null` is a valid "value" for any reference type. However, as I already commented above, **`null` is not an iterator over a set of elements**, which is what the JavaDoc of `Iterable#iterator()`'s method says it returns. – Matt Ball Jun 07 '14 at 12:37