Question

In Java, I need to return an Iterator from my method. My data comes from another object which usually can give me an iterator so I can just return that, but in some circumstances the underlying data is null. For consistency, I want to return an "empty" iterator in that case so my callers don't have to test for null.

I wanted to write something like:

public Iterator<Foo> iterator() {
   if (underlyingData != null) {
      return underlyingData.iterator();  // works
   } else {
      return Collections.emptyList().iterator();  // compiler error
   }
}

But the Java compiler complains about the returning Iterator<Object> instead of Iterator<Foo>. Casting to (Iterator<Foo>) doesn't work either.

Was it helpful?

Solution

You can get an empty list of type Foo through the following syntax:

return Collections.<Foo>emptyList().iterator();

OTHER TIPS

Java 7 has been out for a long time now. Unless you're developing for a previous Java version, you would return an empty iterator like this:

return Collections.emptyIterator();

I'd go more along the lines of

public Iterator<Foo> iterator() {
    if (underlyingData == null)
        return Collections.<Foo> emptyList().iterator();
    return underlyingData.iterator();
}

Just, handle the special case and return, then handle the normal case. But my main point is that you can avoid the assignment with

Collections.<Foo> emptyList().iterator();

The annoyance of Collections.<Foo>emptyList().iterator() is the main reason we provide Iterators.emptyIterator() in google-collections. No type parameter needed, in cases like yours.

I guess this shows that Java type inference doesn't work in every case and that the ternary operator is not always equivalent to the apparently equivalent if-else construct.

I also want to state avoid null. Also avoid passing Iterators about, because they have strange stateful behaviour (prefer Iterable). However, assuming you have a legitimate, non-premature reason for doing this, my preferred way of writing it would be

public Iterator<Foo> iterator() {
    return getUnderlyingData().iterator();
}
private List<Foo> getUnderlyingData() {
    if (underlyingData == null) {
        return Collections.emptyList();
    } else {
        return underlyingData;
    }
}

IMO, it's better not to insert the inferable type information if it can be inferred (even if it makes your code longer).

You are almost certainly going to do it more than once, so insert a getUnderlyingData method instead of just declaring a local variable.

You are calling iterator on both results, so do not repeat yourself.

Sorry, I figured it out. You need to use an assignment so that the compiler can figure out the parameterized type.

public Iterator<Foo> iterator() {
   if (underlyingData != null) {
      return underlyingData.iterator();
   } else {
      List<Foo> empty = Collections.emptyList();  // param type inference
      return empty.iterator();
   }
}
public  final class EmptyIterator{

    public static Iterator iterator(){
        return new Empty();
    }

    private static class Empty implements Iterator {
        public boolean hasNext(){
            return false;
        }
        public Object next(){
            throw new NoSuchElementException();
        }
        public void remove(){
        }
    }
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top