8

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?

Koray Tugay
  • 22,894
  • 45
  • 188
  • 319

4 Answers4

35

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());
John Kugelman
  • 349,597
  • 67
  • 533
  • 578
6

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);
Naman
  • 27,789
  • 26
  • 218
  • 353
  • 3
    Good you've mentioned Java9+'s `IntStream.iterate` overloaded version – fps Nov 07 '18 at 12:47
  • The usage of both prefix and postfix increment operators is poor practice and misleading. They mutate a variable here that is a temporary only visible inside the lambda. The only thing that matters is the return value, just return "i+1" – Paul de Vrieze Nov 19 '18 at 09:30
  • @PauldeVrieze I guess you meant the first line of code, which was the first instinct post and agreed, you can see the improvement in the next line of code. Would update both though. – Naman Nov 19 '18 at 09:34
  • 1
    Yes you are correct. I also agree that the second way is better – Paul de Vrieze Nov 19 '18 at 09:49
3

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.

flakes
  • 21,558
  • 8
  • 41
  • 88
  • 22
    Don’t use any construct that misleadingly modifies the parameter variable. Just use `i -> i + 1`. – Holger Nov 07 '18 at 07:27
  • In addition, you can replace `forEach(...)` with `collect(Collectors.toList())` and not initialize `ints` separately. – David Soroko Nov 12 '18 at 22:00
1

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);
developer_hatch
  • 15,898
  • 3
  • 42
  • 75