Java 8 Streams:折叠/抽象流部分

时间:2017-02-18 14:27:08

标签: java java-8 java-stream

说我有这个流:

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

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

我怎样才能看起来像:

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

无需手动展开fnX部件并将它们放在一起(出于维护原因,我希望保持它们不受影响,并用它们表达fnPartX)。

2 个答案:

答案 0 :(得分:14)

你可以用功能来表达和撰写:

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());

函数的输入和输出类型必须相应匹配。

这可以作为更复杂的构图构造的基础,例如:

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);
    }
}

可以这样使用:

Composer.of(list.stream())
    .andThen(fnPart1)
    .andThen(fnPart2)
    .get()
    .collect(Collectors.toList());

答案 1 :(得分:5)

你必须使用flatMap而不是map。我不知道你的类型是什么,所以我称之为T1,T2等。

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

Stream<T2> fnPart1(T1 t1) {
    return Stream.of(t1).map(fn1).map(fn2).filter(fn3);
}

Stream<T3> fnPart2(T2 t2) {
    return Stream.of(t2).flatMap(fn4).map(fn5).filter(fn6).map(fn7);
}

当然你可以删除一些流操作:

Stream<T2> fnPart1(T1 t1) {
    return Stream.of(fn2(fn1(t1))).filter(fn3);
}

Stream<T3> fnPart2(T2 t2) {
    return fn4(t2).map(fn5).filter(fn6).map(fn7);
}

由于fnPart1和fnPart2只处理单个元素,因此可以进一步简化。