What is wrong in my approach to create a list of integers using IntStream and forEach?

Viewed 721

The naive code I have is:

class ${
    public static void main(String[] _) {
        final List<Integer> ints = new ArrayList<>();
        IntStream.iterate(0, i -> i++).limit(5).forEach(val -> ints.add(val));
        System.out.println(ints);
    }
}

where my expectation was to see the following in the console:

[0, 1, 2, 3, 4]

But the actual is:

[0, 0, 0, 0, 0]

It is probably something very simple, but what am I missing?

4 Answers

i++ has the value of i before it's incremented. You need to use the prefix operator.

IntStream.iterate(0, i -> ++i).limit(5).forEach(val -> ints.add(val));

Actually, don't do that. There's no reason to mutate i, it's simply thrown away. Use the side effect free version. That's the whole idea behind functional programming, after all: avoiding side effects.

IntStream.iterate(0, i -> i + 1).limit(5).forEach(val -> ints.add(val));

For the specific case of a stream of consecutive integers you could replace iterate and limit with range:

IntStream.range(0, 5).forEach(val -> ints.add(val));

And finally, it would also be better to collect the stream into a list rather than adding values with forEach. It directly expresses the intention to create a list, which again avoids side effects.

List<Integer> ints = IntStream.range(0, 5).boxed().collect(Collectors.toList());

You are using a postfix i++, instead of a prefix ++i while passing on the value to forEach. Changing to the following shall provide you the expected output :

IntStream.iterate(0, i -> i + 1).limit(5).forEach(ints::add);

Aside, an alternate way of iterating and combining limit with Java9+ is using IntStream.iterate with an IntPredicate as :

IntStream.iterate(0, i -> i < 5, i -> i + 1).forEach(ints::add);

You need to return the incremented value. You postfix incremented a local variable and returned the non-incremented value. Use ++i not i++

final List<Integer> ints = new ArrayList<>();
IntStream.iterate(0, i -> ++i).limit(5).forEach(val -> ints.add(val));
System.out.println(ints);

Edit See John Kugelman's post about using non-mutating operations when programming in a functional style. Using i + 1 will create a new primitive and not mutate the parameter variable.

You could use a print to see what was happend:

final List<Integer> ints = new ArrayList<>();
        IntStream.iterate(0, i -> {
            System.out.println(i);
            return i++;
        }).limit(5)
                .forEach(val -> ints.add(val));
        System.out.println(ints);

In that case, the value of i always will be 0, because the increment occurs after the value is returned, the correct way is

final List<Integer> ints = new ArrayList<>();
        IntStream.iterate(0, i -> {
            System.out.println(i);
            return ++i;
        }).limit(5)
                .forEach(val -> ints.add(val));
        System.out.println(ints);
Related