Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Java 8 Streams: Collapse/abstract streams parts

Say I have this Stream:

list.stream()
    .map(fn1)      // part1
    .map(fn2)      // 
    .filter(fn3)   // 

    .flatMap(fn4)  // part 2 
    .map(fn5)      //
    .filter(fn6)   //
    .map(fn7)      //
    .collect(Collectors.toList())

How can I make it look like:

list.stream()
    .map(fnPart1)      
    .map(fnPart2)
    .collect(Collectors.toList())

Without manually unwinding the fnX parts and putting them together (for maintenance reasons, I want to keep them untouched, and express the fnPartX with them).

like image 526
BenoitParis Avatar asked Feb 18 '17 14:02

BenoitParis


People also ask

How streams are lazy in Java 8?

Streams are lazy because intermediate operations are not evaluated until terminal operation is invoked. Each intermediate operation creates a new stream, stores the provided operation/function and return the new stream. The pipeline accumulates these newly created streams.

Does Java 8 support streams?

Java 8 offers the possibility to create streams out of three primitive types: int, long and double. As Stream<T> is a generic interface, and there is no way to use primitives as a type parameter with generics, three new special interfaces were created: IntStream, LongStream, DoubleStream.

What are two types of streams in Java 8?

With Java 8, Collection interface has two methods to generate a Stream. stream() − Returns a sequential stream considering collection as its source. parallelStream() − Returns a parallel Stream considering collection as its source.


1 Answers

You could express and compose it with functions:

Function<Stream<T1>, Stream<T2>> fnPart1 = 
        s -> s.map(fn1)
            .map(fn2) 
            .filter(fn3);
Function<Stream<T2>, Stream<T3>> fnPart2 = 
        s -> s.flatMap(fn4)
            .map(fn5)      
            .filter(fn6)   
            .map(fn7);

fnPart1.andThen(fnPart2).apply(list.stream()).collect(Collectors.toList());

The input and output types of the functions have to match accordingly.

This can be the basis for a more complex composition construct such as:

public class Composer<T>{
    private final T element;

    private Composer(T element){
        this.element = element;
    }

    public <T2> Composer<T2> andThen(Function<? super T, ? extends T2> f){
        return new Composer<>(f.apply(element));
    }

    public T get(){
        return element;
    }

    public static <T> Composer<T> of(T element){
        return new Composer<T>(element);
    }
}

This can be used like this:

Composer.of(list.stream())
    .andThen(fnPart1)
    .andThen(fnPart2)
    .get()
    .collect(Collectors.toList());
like image 68
Calculator Avatar answered Sep 29 '22 11:09

Calculator