0

How do I generate a stream of "new" data? Specifically, I want to be able to create data that includes functions that are not reversible. If I want to create a stream from an Array I do

Stream.of(arr)

From a collection

col.stream()

A constant stream can be made with a lambda expression

Stream.generate(() -> "constant")

A stream based on the last input (any reversible function) may be achieved by

Stream.iterate(0, x -> x + 2)

But if I want to create a more general generator (say output of whether a number is divisive by three: 0,0,1,0,0,1,0,0,1...) without creating a new class.

The main issue is that I need to have some way of inputing the index into the lambda, because I want to have a pattern, and not to be dependent on the last output of the function.

Note: someStream.limit(length) may use to stop the length of the stream, so infinite stream generator is actually what I am looking for.

borgr
  • 20,175
  • 6
  • 25
  • 35
  • 4
    https://docs.oracle.com/javase/8/docs/api/java/util/stream/IntStream.html#iterate-int-java.util.function.IntUnaryOperator-, https://docs.oracle.com/javase/8/docs/api/java/util/stream/IntStream.html#range-int-int-, https://docs.oracle.com/javase/8/docs/api/java/util/stream/Stream.html#iterate-T-java.util.function.UnaryOperator- – JB Nizet Sep 20 '17 at 06:07

2 Answers2

3

If you want to have an infinite stream for a function taking an index, you may consider creating a “practically infinite” stream using

IntStream.rangeClosed(0, Integer.MAX_VALUE).map(index -> your lambda)

resp.

IntStream.rangeClosed(0, Integer.MAX_VALUE).mapToObj(index -> your lambda)

for a Stream rather than an IntStream.

This isn’t truly infinite, but there are no int values to represent indices after Integer.MAX_VALUE, so you have a semantic problem to solve when ever hitting that index.

Also, when using LongStream.rangeClosed(0, Long.MAX_VALUE).map(index -> yourLambda) instead and each element evaluation takes only a nanosecond, it will take almost three hundred years to process all elements.

But, of course, there is a way to create a truly infinite stream using

Stream.iterate(BigInteger.ZERO, BigInteger.ONE::add).map(index -> yourLambda)

which might run forever, or more likely, bail out with an OutOfMemoryError once the index can’t be presented in the heap memory anymore, if your processing ever gets that far.

Note that streams constructed using range[Closed] might be more effcient than streams constructed using Stream.iterate.

Holger
  • 285,553
  • 42
  • 434
  • 765
  • Note on the note, iterate is less efficient and more general. It exists for int and long, so when streaming something other than that (or when streaming not in consecutive order) iterate should be used, as in the last example. – borgr Sep 21 '17 at 12:54
  • 1
    @borgr: even the last example could be written as `LongStream.range(0, Long.MAX_VALUE) .mapToObj(BigInteger::valueOf)`, if you can live with the fact that it is not theoretically infinite anymore. For practical purposes, this is preferable and applicable to all tasks where the stream element can be calculated from an index. `iterate` is useful for exactly the use case your question is *not* about, when the calculation of an element needs the previous element (in a nontrivial way). – Holger Sep 21 '17 at 14:51
0

You can do something like this

    AtomicInteger counter = new AtomicInteger(0);

    Stream<Integer> s = Stream.generate(() -> counter.getAndIncrement());
talex
  • 17,973
  • 3
  • 29
  • 66
  • You can even do `Stream.generate(counter::getAndIncrement);` to make it shorter – Ferrybig Sep 20 '17 at 06:17
  • but you do create an instance for that, and you can only increase with that not do anything generic – borgr Sep 20 '17 at 06:26
  • @Ferrybig Yes, but I didn't want to frustrate topic starter with advanced syntax. He may be not familiar with it yet, – talex Sep 20 '17 at 06:27
  • 1
    You can actually skip the variable if you go with a method reference: `Stream.generate(new AtomicInteger()::getAndIncrement);` – shmosel Sep 20 '17 at 07:08
  • @shmosel nice, but I think readability may suffer in this case. It isn't clear from first sight that `new AtomicInteger()` is invoked only once. – talex Sep 20 '17 at 07:31
  • 1
    This stream is infinite, but looping in a way that is not intended in most cases. You may use `IntStream.rangeClosed(0,Integer.MAX_VALUE).boxed()` instead and *if* you ever encounter the difference between them, it is time to rethink what you *actually* want to do with an “infinite” stream that produces ascending `Integer`s (though, `Stream.generate(…)` formally produces an *unordered* stream, even if the generator returns ascending numbers)… – Holger Sep 20 '17 at 09:40
  • @talex It is clear to me. I guess it depends on how comfortable you are with lambdas and method references. – shmosel Sep 20 '17 at 17:44