The yield statement in Ruby, Python and C# makes it very convenient to write complex iterators. As this has been missing in Java so far, here is a class that you can subclass to create generators.
Generator implements an iterator that yields its values one at a time. Subclasses must define a method called #run() and may call yield(T) to return values one at a time.
The generator ends when it reaches a return statement or the end of the method. On the other hand, an generator may run forever and thus yield an infinite sequence (see Example 1 for an example).
Please beware that calling #hasNext() on the generator (and thus any use in a for-each loop) provokes a lookahead of one value. Therefore you cannot repeatedly yield the same object, but rather, you must clone the value on each yield statement (see Example 3 for an example).
NB: this class makes use of Threads, you might want to double-check its source code before using it in a multi-threaded application.
Example 1: Yields an infinite sequence of fibonacci numbers.
Generator<Integer> fibonacci = new Generator<Integer>() {
@Override
public void run() {
int a = 0, b = 1;
while (true) {
a = b + (b = a);
yield(a);
}
}
};
for (int x : fibonacci) {
if (x > 20000) break;
System.out.println(x);
}Example 2: Yields all characters of the string "Hello, Worlds!".
Generator<char>> hello = new Generator<char>() {
@Override
public void run() {
String str = "Hello, Worlds!";
for (int n = 0; n < str.length; n++) {
yield(str.atChar(n));
}
}
};
for (char each : hello) {
System.out.println(each);
}Example 3: Yields all perutations of an array.
public static <T> Generator<T\[]> permute(final T\[] a) {
return new Generator<T\[]>() {
@Override
public void run() {
permute(a.length - 1);
}
private void permute(int n) {
if (n == 0) yield(a.clone());
else for (int k = n; k >= 0; k--) {
swap(n,k);
permute(n - 1);
swap(n,k);
}
}
private void swap(int n, int m) {
T temp = a\[n];
a\[n] = a\[m];
a\[m] = temp;
}
};
}
Contact –