Everything can be a return type: an enum, a class, an interface, an int, an exception etc.
Iterable
is an interface
which could be used to use the return in a foreach call (that's why you can use for(T something : AnArrayList)
because ArrayList<T>
implements Iterable<T>
)
Now, my answer contains an example:
We have a method getNeighbours
which returns Iterable<ClientInterface>
public Iterable<ClientInterface> getNeighbours()
{
return new Iterable<ClientInterface>();
}
Well, ok since Iterable
is just an interface we need to implement methods or use an implementation.
Since it's something which we should do manually we should implement the methods by ourself.
The only method (in Java8, there are 3 methods but we will ignore it) is iterator()
which returns an iterator
.
public Iterable<ClientInterface> getNeighbours()
{
return new Iterable<ClientInterface>()
{
@Override
public Iterator<ClientInterface> iterator()
{
return null;
}
};
}
Iterator
is another interface which is used to provide the logic to iterate over the collection, a list of items etc.
We are forced to implements two methods: hasNext and next
hasNext
is used to determinate if there are more items to iterate over, next
is used to iterate over it.
public Iterable<ClientInterface> getNeighbours()
{
return new Iterable<ClientInterface>()
{
@Override
public Iterator<ClientInterface> iterator()
{
return new Iterator<ClientInterface>()
{
@Override
public boolean hasNext()
{
return false;
}
@Override
public ClientInterface next()
{
return null;
}
};
}
};
}
We here need to remember which was our last position so we would create a field inside our Iterator.
public Iterable<ClientInterface> getNeighbours()
{
return new Iterable<ClientInterface>()
{
@Override
public Iterator<ClientInterface> iterator()
{
return new Iterator<ClientInterface>()
{
private int position;
@Override
public boolean hasNext()
{
return false;
}
@Override
public ClientInterface next()
{
return null;
}
};
}
};
}
Here the problem: What we should iterate? It depends to you, an example could be:
public Iterable<ClientInterface> getNeighbours()
{
return new Iterable<ClientInterface>()
{
@Override
public Iterator<ClientInterface> iterator()
{
return new Iterator<ClientInterface>()
{
private int position;
private ClientInterface[] items = new ClientInterface[]{new ClientInterface(), new ClientInterface()};
@Override
public boolean hasNext()
{
return position != items.length;
}
@Override
public ClientInterface next()
{
if (!hasNext()) throw new NoSuchElementException();
return items[position++];
}
};
}
};
}
Note here how we created an array of items and used our two methods hasNext
and next
to provide a way to iterate over it.
Every call of next
increment the internal pointer, and our hasNext method just checks if the pointer reached the end of the array.
Collections like ArrayList
, LinkedList
etc. already did the job for you and better (implements remove
method) you can get this iterator by using ArrayList.iterator()
Now you could write something like:
for (ClientInterface el : yourClass.getNeighbours())
{
System.out.println(el);
}