在 Java 中折叠顺序流

Folding a sequential stream in Java

我习惯用 Scala 编程,但我不得不写一些 Java,我正在尝试执行与以下 Scala 片段等效的代码:

trait Options[K, V] {
  def add(key: K , value: V): Options[K, V]
}

val options: Options[T, U] = ???
val elems: List[(T, U)] = ???
elems.foldLeft(options) {
  case (opts, (key, value)) => opts.add(key, value)
}

也就是说,我将 elems 上的元素折叠到 options 中,每一步都生成一个新实例。

我尝试使用 Java 的 Stream#reduce:

interface Options<K, V> {
  Options<K, V> add(K key, V value);
}

Options<K, V> options = ???
Stream<Tuple2<K, V>> elems = ??? // This is Reactor's Tuple2
elems.reduce(options, (opts, opt) -> opts.add(opt), ???)

我不知道组合器应该是什么,而且我很难想象它的参数会有什么值。我的理解是 combiner 将用于合并并行流中并行生成的中间值。在我的例子中,我根本不关心并行处理 elems 。换句话说,我正在寻找 Flux#reduce.

的同步和顺序版本

我无法控制 Options 的 API。 elems 不需要是 Stream.

无法使用您提供的接口编写组合器。问题是组合器需要一种方法来组合两个 Options 但没有办法做到这一点。任何人都可以对 Options 实例做的唯一一件事就是向它添加一对。我无法从中得到任何信息。它大概不能做任何非常有用的事情。

也许这个问题源于 Java 没有特征,Java 接口也不是特征的合适替代品。

惯用的 Java 写法只是一个标准的 for 循环:

Options<String, String> options = /*whatever*/;
List<Pair<String, String>> elems = /*whatever*/;
for (Pair<String, String> pair : elems)
{
    options = options.add(pair.getKey(), pair.getValue());
}

如果您可以处理永远无法使用并行流的事实,那么您可以利用顺序流永远不会真正使用组合器这一事实。因此,您可以编写一个 Collector 来定义一个只会抛出异常的组合器。

Options<String, String> foo = elems.stream()
    .collect(
        () -> options,
        (opt, pair) -> opt.add(pair.getKey(), pair.getValue()),
        (a, b) -> { throw new UnsupportedOperationException(); }
    );

如果您真的想使用 reduce,您需要修改您的界面以公开有关它包含的键值对的一些信息或提供一种添加多个键的方法-值对一次。例如:

interface Options<K, V>
{
    Options<K, V> add(K key, V value);
    Options<K, V> add(Options<K, V> otherOptions);
}

Options<String, String> options = /*whatever*/;
List<Pair<String, String>> elems = /*whatever*/;

Options<String, String> foo = elems.stream()
    .reduce(
        options,
        (opt, pair) -> opt.add(pair.getKey(), pair.getValue()),
        Options::add
    );

我怀疑这不是您想听到的,但 Scala 和 Java 是不同的语言。您不应该期望所有事物都具有精确的相似性。如果是这样,那么就没有理由同时存在这两种语言。