HiveBrain v1.2.0
Get Started
← Back to all entries
patternjavaMinor

Using a Pythonesque range() generator function with the Java foreach loop

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
thepythonesquewithrangeloopfunctionjavageneratorusingforeach

Problem

Now that we have the nice new foreach loop in Java, the old-style loop looks ugly be comparison.

I like the way Python has a range() generator that allows the foreach construct to iterate over a range of integers.

I have written a Range class which allows this. Please provide comments.

```
package highland.mark;

import java.util.Iterator;

/**
* A class to enable java's 'foreach' loop to accept a range.
*
* This allows replacing the C style:
*
*
*
* for (int i = 0; i
*
*
* with:
*
*
*
* for (int i : range(10)) {...}
*
*
*
* Three versions of range() are provided allowing combinations of start, end,
* and step.
*
* @author Mark Thomas
* @version 1.0
*/
public final class Range implements Iterator, Iterable {

/**
* The next integer to be returned by the iterator.
*
*/
private int next;
/**
* The last integer to be returned will be (next - 1).
*/
private final int to;
/**
* The increment added to the value of next after each iteration.
*/
private final int step;

/**
* A Method to be used with the java 'foreach' loop.
*
* Usage:
*
*
*
* import static highland.mark.Range.range;
* ...
* for (int i : range(from, to, step)) {...}
*
*
*
* @param from
* : int, first value returned.
* @param to
* : int, one more than last value returned.
* @param step
* : int, increment for each iteration (may be negative so long
* as (to .
* @return An Iterable which supplies an Iterator which,
* on each iteration, returns integers from from to
* (to - 1) incrementing by step each
* time.
* @throws IllegalArgumentException
* if step == 0 or step is the wrong
* sign.
*/
public static Iterable range(int from, int to, int step)

Solution

For the most part, this appears to be neat, and well structured.

There is a significant bug, though:

  • Iterable implies an iterator() method. Each time you call that iterator() method you should get a new instance of an interator, not an 'expired' instance.



For example, the following code should print the numbers 1 to 10 twice....

Range onetoten = Range.range(1, 10, 1);

for (Integer i : onetoten) {
    System.out.println(i);
}

for (Integer i : onetoten) {
    System.out.println(i);
}


Your code will only print them once.

The fix for this is to store the from value as well as the to and the step, and to then return a duplicate Range in the iterator() method.

EDIT: I should point out this: IntStream.rangeClosed() (Java8)

IntStream.rangeClosed(1, 10).forEach(i -> System.out.println(i));

Code Snippets

Range onetoten = Range.range(1, 10, 1);

for (Integer i : onetoten) {
    System.out.println(i);
}

for (Integer i : onetoten) {
    System.out.println(i);
}
IntStream.rangeClosed(1, 10).forEach(i -> System.out.println(i));

Context

StackExchange Code Review Q#45535, answer score: 8

Revisions (0)

No revisions yet.