-2
int val = integerList.stream().collect(
        Collectors.reducing(0, a1 -> a1 * 5, (a1, a2) -> a1 + a2));

上面的代码进行了归约操作。将整数流和聚合函数转换为返回 Integer 。我无法理解以下代码和归约操作的内部实现。Java 如何执行以下有状态功能?谢谢!

java.util.stream.Collectors:reducing method
    public static <T, U>
    Collector<T, ?, U> reducing(U identity,
                                Function<? super T, ? extends U> mapper,
                                BinaryOperator<U> op) {
        return new CollectorImpl<>(
                boxSupplier(identity),
                (a, t) -> { a[0] = op.apply(a[0], mapper.apply(t)); },
                (a, b) -> { a[0] = op.apply(a[0], b[0]); return a; },
                a -> a[0], CH_NOID);
    }

可能是,我会更好地澄清我的问题。上述实现如何获取数据流。a[0],b[0] 是指数据流吗?我相信以上内容为供应商和累加器提供了功能实现。我想了解减少过程是如何通过代码进行的。

4

1 回答 1

6

该函数接受三个参数:

  • 第一个是身份。减少流时,您必须从某个地方开始(否则,减少空列表会产生什么结果?)。标识是应用于链中第一个归约操作的第一个参数的对象

  • 第二个是映射器。reducing()是一种通用操作 - 您可以将 type 流的元素减少为 typeT的最终结果U,因此您必须提供一个中间操作,该操作U从 type 元素提供 typeT元素。如果T == U并且您不想进行转换,则可以在此处提供身份功能

  • 第三个参数是归约函数 - 这是按顺序应用于流元素的函数,从标识开始

所以,举个例子:

如果您只想将Integer流的元素汇总为整数,则可以使用Collectors.reducing(0, x -> x, (x, y) -> x + y).

如果要总结流中Strings的长度String,可以使用Collectors.reducing(0, String::length, (x, y) -> x + y).

如果您想Double从 s 字符串中获取最大值Double,但不小于Math.PI,您可以使用Collectors.reducing(Math.PI, x -> x, Math::max).

此外,如果您希望您的归约是有状态的,请记住您可以将归约器用作对对象内部方法的引用。这样,对象就可以用来保持状态。例如,这里有一个“taxing reductor”,每增加 100 次就增加 1 个“tax”:

public class Taxer implements BinaryOperator<Integer> {
 int counter = 0;

 @Override
 public Integer apply(Integer i1, Integer i2) {
  counter++;
  if (counter % 100 == 0) {
   return i1 + i2 + 1;
  } else {
   return i1 + i2;
  }
 }
}

...

Taxer t = new Taxer();

...

.collect(Collectors.reducing(0, x -> x, t);

同样可以扩展使用以实现复杂的情况,例如groupingBy

Map<String, Integer> output = Stream.of("this", "word", "is", "the", "best")
    .collect(Collectors.groupingBy(x-> x.substring(0, 1),
            Collectors.reducing(0, x-> x.length(), (x, y)-> x + y)));

这里首先输入字符串根据它们开始的字符进行分组,然后将长度相加

于 2019-06-03T11:19:46.840 回答