The best reusable option is to implement the interface Iterable and override the method iterator().
Here's an example of a an ArrayList like class implementing the interface, in which you override the method Iterator().
import java.util.Iterator;
public class SOList<Type> implements Iterable<Type> {
private Type[] arrayList;
private int currentSize;
public SOList(Type[] newArray) {
this.arrayList = newArray;
this.currentSize = arrayList.length;
}
@Override
public Iterator<Type> iterator() {
Iterator<Type> it = new Iterator<Type>() {
private int currentIndex = 0;
@Override
public boolean hasNext() {
return currentIndex < currentSize && arrayList[currentIndex] != null;
}
@Override
public Type next() {
return arrayList[currentIndex++];
}
@Override
public void remove() {
throw new UnsupportedOperationException();
}
};
return it;
}
}
This class implements the Iterable interface using Generics. Considering you have elements to the array, you will be able to get an instance of an Iterator, which is the needed instance used by the "foreach" loop, for instance.
You can just create an anonymous instance of the iterator without creating extending Iterator and take advantage of the value of currentSize to verify up to where you can navigate over the array (let's say you created an array with capacity of 10, but you have only 2 elements at 0 and 1). The instance will have its owner counter of where it is and all you need to do is to play with hasNext(), which verifies if the current value is not null, and the next(), which will return the instance of your currentIndex. Below is an example of using this API...
public static void main(String[] args) {
// create an array of type Integer
Integer[] numbers = new Integer[]{1, 2, 3, 4, 5};
// create your list and hold the values.
SOList<Integer> stackOverflowList = new SOList<Integer>(numbers);
// Since our class SOList is an instance of Iterable, then we can use it on a foreach loop
for(Integer num : stackOverflowList) {
System.out.print(num);
}
// creating an array of Strings
String[] languages = new String[]{"C", "C++", "Java", "Python", "Scala"};
// create your list and hold the values using the same list implementation.
SOList<String> languagesList = new SOList<String>(languages);
System.out.println("");
// Since our class SOList is an instance of Iterable, then we can use it on a foreach loop
for(String lang : languagesList) {
System.out.println(lang);
}
}
// will print "12345
//C
//C++
//Java
//Python
//Scala
If you want, you can iterate over it as well using the Iterator instance:
// navigating the iterator
while (allNumbers.hasNext()) {
Integer value = allNumbers.next();
if (allNumbers.hasNext()) {
System.out.print(value + ", ");
} else {
System.out.print(value);
}
}
// will print 1, 2, 3, 4, 5
The foreach documentation is located at http://download.oracle.com/javase/1,5.0/docs/guide/language/foreach.html. You can take a look at a more complete implementation at my personal practice google code.
Now, to get the effects of what you need I think you need to plug a concept of a filter in the Iterator... Since the iterator depends on the next values, it would be hard to return true on hasNext(), and then filter the next() implementation with a value that does not start with a char "a" for instance. I think you need to play around with a secondary Interator based on a filtered list with the values with the given filter.
Answer from Marcello DeSales on Stack OverflowThe best reusable option is to implement the interface Iterable and override the method iterator().
Here's an example of a an ArrayList like class implementing the interface, in which you override the method Iterator().
import java.util.Iterator;
public class SOList<Type> implements Iterable<Type> {
private Type[] arrayList;
private int currentSize;
public SOList(Type[] newArray) {
this.arrayList = newArray;
this.currentSize = arrayList.length;
}
@Override
public Iterator<Type> iterator() {
Iterator<Type> it = new Iterator<Type>() {
private int currentIndex = 0;
@Override
public boolean hasNext() {
return currentIndex < currentSize && arrayList[currentIndex] != null;
}
@Override
public Type next() {
return arrayList[currentIndex++];
}
@Override
public void remove() {
throw new UnsupportedOperationException();
}
};
return it;
}
}
This class implements the Iterable interface using Generics. Considering you have elements to the array, you will be able to get an instance of an Iterator, which is the needed instance used by the "foreach" loop, for instance.
You can just create an anonymous instance of the iterator without creating extending Iterator and take advantage of the value of currentSize to verify up to where you can navigate over the array (let's say you created an array with capacity of 10, but you have only 2 elements at 0 and 1). The instance will have its owner counter of where it is and all you need to do is to play with hasNext(), which verifies if the current value is not null, and the next(), which will return the instance of your currentIndex. Below is an example of using this API...
public static void main(String[] args) {
// create an array of type Integer
Integer[] numbers = new Integer[]{1, 2, 3, 4, 5};
// create your list and hold the values.
SOList<Integer> stackOverflowList = new SOList<Integer>(numbers);
// Since our class SOList is an instance of Iterable, then we can use it on a foreach loop
for(Integer num : stackOverflowList) {
System.out.print(num);
}
// creating an array of Strings
String[] languages = new String[]{"C", "C++", "Java", "Python", "Scala"};
// create your list and hold the values using the same list implementation.
SOList<String> languagesList = new SOList<String>(languages);
System.out.println("");
// Since our class SOList is an instance of Iterable, then we can use it on a foreach loop
for(String lang : languagesList) {
System.out.println(lang);
}
}
// will print "12345
//C
//C++
//Java
//Python
//Scala
If you want, you can iterate over it as well using the Iterator instance:
// navigating the iterator
while (allNumbers.hasNext()) {
Integer value = allNumbers.next();
if (allNumbers.hasNext()) {
System.out.print(value + ", ");
} else {
System.out.print(value);
}
}
// will print 1, 2, 3, 4, 5
The foreach documentation is located at http://download.oracle.com/javase/1,5.0/docs/guide/language/foreach.html. You can take a look at a more complete implementation at my personal practice google code.
Now, to get the effects of what you need I think you need to plug a concept of a filter in the Iterator... Since the iterator depends on the next values, it would be hard to return true on hasNext(), and then filter the next() implementation with a value that does not start with a char "a" for instance. I think you need to play around with a secondary Interator based on a filtered list with the values with the given filter.
Sure. An iterator is just an implementation of the java.util.Iterator interface. If you're using an existing iterable object (say, a LinkedList) from java.util, you'll need to either subclass it and override its iterator function so that you return your own, or provide a means of wrapping a standard iterator in your special Iterator instance (which has the advantage of being more broadly used), etc.
so I know how to implement (e.g public Iterator<E> iterator() { return new ListIterator<E>(//could add first element here); }
but sometimes I see it saying public iterable. what's the difference? I think it is iterator is like you go through it once and you're done but iterable you get back a list that you can go through over and over again?
if it helps the thing I'm having trouble about is this: http://coursera.cs.princeton.edu/algs4/assignments/8puzzle.html
public Iterable<Board> neighbors()
do I just have to return a linked list of some sort (stack/queue)? why not use iterator<Board> instead?
Edit: I got it, you're returning an object that is iterable itself.
Hi,
According to my understanding of Iterator and Iterable:
-
Iterableis used when you want to get for - each for a collection.Iteratoris still used behind the scenes to fetch the items for for-each. -
If I just want to go through a collection ( don't want for-each) , I can just implement Iterator interface on collection class and it should work. Note -
Iterableis not necessary. -
If I implement
Iteratorinterface on a collection class, It gives me the ability to iterate over the collection . Now if I implement the 'for-each' method (defined inIterableInterface ) in the class , then I can get a for-each loop for the collection , even without implementingIterable.
is it correct?
Thanks
Variables
I understand why you have the Range.this.end and Range.this.start to avoid confusion about where those variables come from... If you need the Range.this as part of the teaching exercise, then sure. Otherwise, I would recommend three things....
- add
rangeas a prefix, even though it is slightly redundant - Make them final...
- one variable per line... (it makes revision-control diffs/patches easier to read)
The code would look like:
private final int rangeStart;
private final int rangeEnd;
Then, all the Range.this.start would be just rangeStart, etc.
Nested classes
Your iterator class is a non-static class, so it can reference the outer class's range start/end.
In this case, the nested class can be changed to a static class very easily. This has the potential of simplifying memory management because the iterator does not need a reference to the enclosing Range.
Consider a private-static Iterator instance:
// Inner class example
private static final class RangeIterator implements
Iterator<Integer> {
private int cursor;
private final int end;
public RangeIterator(int start, int end) {
this.cursor = start;
this.end = end;
}
public boolean hasNext() {
return this.cursor < end;
}
public Integer next() {
if(this.hasNext()) {
int current = cursor;
cursor ++;
return current;
}
throw new NoSuchElementException();
}
public void remove() {
throw new UnsupportedOperationException();
}
}
This static class removes the need for the back-references to Range.this entirely....
The new iterator is called simply with:
public Iterator<Integer> iterator() {
return new RangeIterator(start, end);
}
Pre-Validate
It is better to pre-validate state, than to fall-through to an error... This code:
public Integer next() { if(this.hasNext()) { int current = cursor; cursor ++; return current; } throw new NoSuchElementException(); }
would be better as:
public Integer next() {
if(!this.hasNext()) {
throw new NoSuchElementException();
}
int current = cursor;
cursor ++;
return current;
}
Post-Increment
This block can be simplified:
int current = cursor; cursor ++; return current;
to just:
return cursor++;
although I imagine this is done as an education ploy.
Integer as the example
Because of the int autoboxing I worry that Integer may not be the right choice for data type. You may want to consider a non-primitive as the data.
Autoboxing is the sort of thing that will confuse.
Conclusion
Otherwise, I don't see much in the way of problems.
Overall, it's pretty good code to learn from.
Functionality
I like that you've used the inclusive-exclusive convention for the lower and upper bounds, respectively. The rationale for that design would be an interesting discussion topic.
I suggest adding a second constructor for convenience:
public Range(int end) {
this(0, end);
}
There should probably be getters for start() and end(). Technically, you should override .equals() and .hashCode() as well, but maybe it's OK to leave them out for simplicity.
Style
As @rpg711 noted, putting the @Override annotation everywhere would be good practice. It would also help students see which methods are mandatory parts of the interface (well, practically all of them).
JavaDoc would be a good habit to teach. At the least, document the outer class and inner class, and probably their constructors as well.
It would be more conventional to put a space after the if, for, and while keywords. They look less like function calls that way.
Declaring start and end as final could help emphasize to students that the Range is immutable, and only the RangeIterator changes state. Perhaps adding final would alleviate some of @rolfl's concerns about the inner class referring to Range.this.start and Range.this.end.
In agreement with @rolfl, I would also personally prefer
@Override
public Integer next() {
if (!this.hasNext()) {
throw new NoSuchElementException();
}
// The post-increment magically takes effect _after_
// returning. This is equivalent to
//
// int value = this.cursor++;
// return value;
//
return this.cursor++;
}
… though I can understand if you choose not to burden the students with that trivia.
Test case
It would be useful to illustrate that two RangeIterators keep state independently. Perhaps this might make a good example?
Range digits = new Range(0, 10);
for (Integer tensDigit : digits) {
for (Integer onesDigit : digits) {
System.out.format("%s%s ", tensDigit, onesDigit);
}
System.out.println();
}