用Java折叠顺序流

时间:2019-01-28 15:27:25

标签: java functional-programming java-stream reduce fold

我曾经在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)
}

也就是说,我将elemsoptions上的元素折叠起来,并在每个步骤中生成一个新实例。

我尝试使用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

1 个答案:

答案 0 :(得分:3)

无法使用您提供的接口编写组合器。问题是组合器需要一种将两个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是不同的语言。您不应该期望所有东西都具有完全相同的东西。如果确实如此,那么就没有理由同时存在两种语言。