8

How do I replace the Supplier code here with lambda expression

IntStream inStream = Stream.generate(new Supplier<Integer>() {
    int x= 1;
    @Override
    public Integer get() {
        return x++ ;
    }
}).limit(10).mapToInt(t -> t.intValue());
inStream.forEach(System.out::println);

The output of above piece of code is:

1
2
3
4
5
6
7
8
9
10
Nikolas Charalambidis
  • 40,893
  • 16
  • 117
  • 183
Shiva
  • 1,962
  • 2
  • 13
  • 31

3 Answers3

8

The Stream::generate is not suitable for this issue. According to the documentation:

This is suitable for generating constant streams, streams of random elements, etc.

  • You might want to use rather IntStream::range:

    IntStream intStream = IntStream.range(1, 11);
    intStream.forEach(System.out::println);
    
  • Another solution might be using the IntStream.iterate where you can control the increment comfortably using the IntUnaryOperator:

    IntStream intStream = IntStream.iterate(1, i -> i+1).limit(10);
    intStream.forEach(System.out::println);
    
  • As said, the Stream::generate is suitable for the constant streams or random elements. The random element might be obtained using the class Random so here you might want to get an increment using AtomicInteger:

    AtomicInteger atomicInteger = new AtomicInteger(1);
    IntStream intStream = Stream.generate(atomicInteger::getAndIncrement).limit(10);
    intStream.forEach(System.out::println);
    
Nikolas Charalambidis
  • 40,893
  • 16
  • 117
  • 183
  • Thanks @nikolas. The `IntStream.range(1, 11)` is simple and elegant. I thought I will do it using lambda too. – Shiva Dec 01 '18 at 15:22
  • You might use `Stream.generate(() -> atomicInteger.getAndAdd(2)) .limit(10).mapToInt(Integer::intValue);` for the odd numbers. – Nikolas Charalambidis Dec 01 '18 at 15:24
  • @Nikolas that's why I would prefer suggesting `Stream.iterate` rather. – Naman Dec 01 '18 at 15:26
  • @nullpointer: I have added the solution with `Stream.iterate` which seems to be the best. However, there are plenty of ways and it depends on the use case :) – Nikolas Charalambidis Dec 01 '18 at 15:28
  • 1
    Oh, ya I missed it. Don't mutate variables within the stream, `i -> ++i` to `i -> i+1` would better. – Naman Dec 01 '18 at 15:29
  • 1
    might just be me but I feel `IntStream.rangeClosed(1, 10);` is more intuitive for this task instead of `IntStream.range(1, 11);`. the `range` function would be the ideal one in the case of generating array/list indices etc. but anyway matter of choice I guess. – Ousmane D. Dec 01 '18 at 15:52
  • @Aomine: Those two methods are both a matter of choice since the integer definition. I prefer `IntStream::range` since it's shorter itself and I am aware of the classical `for (int i=1; i<11; i++)` which iterates from `1` to `10` inclusive while `11` being used. :) Right, a matter of choice. – Nikolas Charalambidis Dec 01 '18 at 21:32
  • 1
    @Nikolas fair enough, that's why I mentioned "might be just me...". I guess we're agreed on this one then.. "a matter of choice" ;-). – Ousmane D. Dec 01 '18 at 21:36
  • 1
    Might be more natural to write `IntStream.rangeClosed(1, 10)` here. And, by the way, using `IntStream.generate(new AtomicInteger(1)::getAndIncrement) .limit(10)` in the first place, makes the `.mapToInt(Integer::intValue)` unboxing step obsolete. – Holger Dec 03 '18 at 11:04
5

Or you can use this

IntStream.iterate(1, i -> i + 1)
 .limit(10)
 .forEach(System.out::println);  
Hadi J
  • 16,989
  • 4
  • 36
  • 62
3

Something like this if you're bound to use Stream.generate specifically :

IntStream inStream = Stream.generate(new AtomicInteger(1)::getAndIncrement)
        .limit(10)
        .mapToInt(t -> t);
inStream.forEach(System.out::println);

Edit: Using IntStream.generate, you can perform it as

IntStream.generate(new AtomicInteger(1)::getAndIncrement).limit(10);

Note: A better solution in terms of the API design would definitely be to make use of Stream.iterate for such a use case.

Naman
  • 27,789
  • 26
  • 218
  • 353
  • @secretsuperstar Ya I overlooked the `x` being treated as atomic there. Updated now. – Naman Dec 01 '18 at 15:16
  • 2
    I like the `new AtomicInteger(1)::getAndIncrement` method reference - too way comfortable :) – Nikolas Charalambidis Dec 01 '18 at 15:29
  • Using `IntStream.generate(new AtomicInteger(1)::getAndIncrement) .limit(10)` in the first place, makes the `.mapToInt(t -> t)` unboxing step obsolete. – Holger Dec 03 '18 at 11:06
  • @Holger nice point, but I've used `Stream.generate` as posted in the question. I believe that would require me to `map` it as a must. – Naman Dec 03 '18 at 11:46
  • 5
    I don’t see why you have to use `map` here. The OP showed code producing an `IntStream` eventually, hence, it’s worth pointing out that creating a `Stream` first, just to invoke `.mapToInt(t -> t)` afterwards, is more complicated *and* less efficient than the straight-forward approach. If you truly needed a `Stream`, using `IntStream.generate(new AtomicInteger(1)::getAndIncrement) .limit(10) .boxed()` still would be simpler than using `map`. – Holger Dec 03 '18 at 12:10