Internal and External truncation conditions

Zhong Yu zhong.j.yu at
Sat Feb 9 20:59:10 PST 2013

On Sat, Feb 9, 2013 at 10:25 PM, Zhong Yu <zhong.j.yu at> wrote:
> Based on my own use cases, code that needs forEachUntil() usually
> intends to process just enough elements to produce a result, for
> example, a lexer scans a char stream until it yields a token. In that
> sense forEachUntil() is really an aggregator for *some* elements. We
> may have a method in the form of
>     interface Stream<T>
>         <R> R scan(Function<T,R> scanner)
> The scanner is usually stateful. Elements are fed to the scanner,
> until it returns a non-null value; that value is the return value of
> scan(). If end of stream is reached before scanner returns non-null,
> scan() returns null. A scanner may need to react to EOF event, the
> application can design an EOF sentinel of type T.
> In the parallel case, scanner must be thread-safe; if it returns
> non-null for one split, it should return non-null for all splits at
> around the same time; one of the non-null values is chosen arbitrarily
> as the result of scan().
> If null sentinel is too distasteful, scanner can return Optional<R>;
> or it can yield result into a Consumer<R> sink.
> Examples:
>     Collection<Int> primes = ints.parallel().scan( gather primes till xxx );
>     Paragraph para = lines.scan( gather lines till an empty line or EOF );
> scan() is only intended for part of the stream. To turn the whole
> stream into another stream, say a line stream into a paragraph stream,
> flatMap(FlatMapper) should work just fine.

Actually, scan() can be defined in term of

    flatMap(FlatMapper mapper).findFirst()

the mapper is stateful; it gathers some elements then yields a result
to the sink.

The scan() method, though providing the same functionality, is more
clear about the intention of the programmer.

Zhong Yu

More information about the lambda-libs-spec-observers mailing list