foldfold和Java收集有什么区别

问题描述

此问题针对Vavr(Java的FP库),但可能适用于Scala或其他可以与Java进行比较的FP语言。

Vavr foldLeft和有什么区别:

  •  <U> U foldLeft(U zero,BiFunction<? super U,? super T,? extends U> combiner)
    

和Java的collect

  • <R> R collect(supplier<R> supplier,BiConsumer<R,? super T> accumulator,R> combiner)
    

似乎两者都可以达到相同的目的:遍历一个集合(例如Stream<T>),并在遍历时将结果累加成新的U(或R)类型。

乍一看,签名在#参数中有所不同,并且Java collect似乎打算在并行块中运行。

概念上实际存在哪些差异? Vavr foldLeft似乎更易于使用。

一个非常愚蠢的例子只是为了说明:

Vavr foldLeft

// result = "HelloFunctionalWorld"
String result = Seq("Hello","Functional","World")
    .foldLeft(new StringBuilder(),(acc,word) -> acc.append(word))
    .toString();

Java collect

// result = "HelloFunctionalWorld"
final String result = Arrays.asList("Hello","World").stream()
    .collect(
        StringBuilder::new,word) -> acc.append(word),StringBuilder::append
    )
    .toString();

解决方法

概念上实际存在哪些差异?

collect(Supplier<R> supplier,BiConsumer<R,? super T> accumulator,R> combiner)的Javadoc说:

对此流的元素执行mutable reduction操作。可变归约是其中归约值是可变结果容器(例如ArrayList),并且通过更新结果的状态而不是通过替换结果来合并元素。产生的结果等于:

R result = supplier.get();
for (T element : this stream)
    accumulator.accept(result,element);
return result;

这里的关键词是可变,因为Vavr不会做任何可变的事情,而是一个功能库。

问题中使用StringBuilder的示例实际上违反了功能原理。如果您不想遵循功能范式,为什么要使用Vavr?


foldLeft()等效的Java Stream是reduce(),您是正确的,第3个参数是支持并行处理:

// Vavr
<U> U foldLeft​(U zero,BiFunction<? super U,​? super T,​? extends U> combine)

// Java Stream
<U> U reduce(U identity,BiFunction<U,? super T,U> accumulator,BinaryOperator<U> combiner)

如果结果类型与流元素类型相同,则将使用以下替代方法,它们不需要第3个参数即可支持并行处理:

// Vavr
T fold​(T zero,BiFunction<? super T,​? extends T> combine)

// Java Stream
T reduce(T identity,BinaryOperator<T> accumulator)

更新方法比较:

Vavr

Java流