【问题标题】:What's the difference b/w foldLeft and Java collectb/w foldLeft 和 Java collect 有什么区别
【发布时间】:2020-10-23 18:42:41
【问题描述】:

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

VavrfoldLeft有什么区别:

  •  <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,
                  BiConsumer<R, R> combiner)
    

似乎两者都可以达到相同的目的:通过遍历一个集合(比如Stream&lt;T&gt;)并在遍历时将结果累积为一个新类型U(或R)。

乍一看,#arguments 中的签名不同,Java collect 似乎打算在并行块中运行。

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

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

VavrfoldLeft:

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

Javacollect:

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

【问题讨论】:

  • 嗨@NathanHughes,我想我应该在问题中介绍Java reduce 操作,因为我看不出reducecollect 对于特别笨的人的区别例子。
  • 对于它的价值,我认为阶乘在这里是一个更好的玩具示例,例如,scastie.scala-lang.org/ZxkWbgeRTaa0MbhrOGmG5Q
  • @user,有一个版本的reduce 缩减为不同的类型U,所以流的类型和缩减值的类型可以不同。它们不需要相同。

标签: java scala java-stream vavr


【解决方案1】:

概念上有哪些实际差异?

正如collect(Supplier&lt;R&gt; supplier, BiConsumer&lt;R,? super T&gt; accumulator, BiConsumer&lt;R,R&gt; combiner) 的 javadoc 所说:

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

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

这里的关键词是mutable,因为 Vavr 作为一个函数库不做任何可变的事情。

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


foldLeft()的Java Stream等价物是reduce(),你没看错,第三个参数是支持并行处理:

// 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)

如果结果类型与流元素类型相同,您将使用以下替代方案,这些替代方案不需要第三个参数来支持并行处理:

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

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

UPDATE方法比较:

Vavr

Java 流

【讨论】:

  • 谢谢@andreas 我看到了累加器的不变性。也许我应该更改原始问题以将 Vavr foldLeft 与 Java reduce 进行比较。
  • @GerardBosch 除了第三个参数,foldLeft/foldreduce 在概念上没有区别,那么您的新问题会问什么?请不要改变问题来提出不同的问题。如果您想问其他问题,请创建一个新问题。
  • “如果你不打算遵循函数式范式,为什么要使用 Vavr?” 真的很有趣,不懂函数式编程的人认为一个简单的、本地的、封装的突变会破坏任何功能代码。在 JVM 中构建字符串非常昂贵,本地字符串构建器即使在纯代码上也完全可以。
  • @user 除了答案中已经提到的第三个参数之外,foldLeftreduce 有什么不同?是的,我同意foldRight 略有不同,而且我从未说过其他话,因为我从未说过任何关于它的事情。
  • 我想我得到了 b/w collectreduce 的细微差别:可变减少,对吧? collect 采用 Biconsumer(因此会改变累加器),而 reduce 采用 BiFunction 每次都会导致一个新的累加器实例(例如,这在持久数据结构的上下文中是有意义的)。所以最后,我猜想与foldLeft 的区别在于后者不打算在并发块中运行,并且保证顺序是连续的。对吗?
猜你喜欢
  • 1970-01-01
  • 2017-04-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-03-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多