List<Integer> integers = Arrays.asList(1, 2, 3, 5, 6, 8, 9, 10);
integers.stream().filter((integer) -> integer % 2 == 0).collect(Collectors.toList());
如上所示,integers
是一个List,我们只需要过滤偶数。我可以使用.filter()
方法实现。但是,是否有可能使用.reduce()
方法实现相同的目标。希望,.reduce()
方法通过执行给定的BynaryOperation并返回简化列表来过滤掉所有其他元素。
如果我对.reduce()
方法的理解不正确,请告诉我这种方法究竟是做什么的。
答案 0 :(得分:10)
您对减少的理解是错误的。 reduce
将重复对所有元素应用函数以获得一个结果。
你似乎认为像做
一样1, 2, 3, 5, 6, 8, 9, 10
│ │ │ │ │ │ │ │
└op┘ └op┘ └op┘ └op┘
│ │ │ │
result list
事实上,它确实
1, 2, 3, 5, 6, 8, 9, 10
│ │ │ │ │ │ │ │
└op┘ └op┘ └op┘ └op┘
│ │ │ │
└─op─┘ └─op─┘
│ │
└────op────┘
│
final result value
虽然这是一个概念视图,但未指定操作的确切顺序。顺序执行将类似于(((1 op 2) op 3) op 4)…
,而并行执行将是执行的混合,如上面的树和部分顺序执行。
如果您首先将每个元素转换为reduce
,然后使用连接每个列表的列表操作,则可以滥用List
来创建结果列表,但是,这有两个问题:< / p>
op
函数,它在每个可能的执行场景中都会这样做。后一点可以通过使用collect
来解决,这是可变缩减,因此,允许您使用可以添加项目的可变列表,但是,它不会解决第一点,包括所需的过滤器会违反合同,只能按顺序执行。
因此,解决方案是为源列表范围内的所有元素定义filter
,然后使用collect
进行可变缩减以创建结果列表,并且非常惊讶,这正是原始代码的作用:
… .filter(integer -> integer % 2 == 0).collect(Collectors.toList());
答案 1 :(得分:8)
您可以使用Stream.reduce(U identity, BiFunction<U,? super T,U> accumulator, BinaryOperator<U> combiner)
方法,该方法有三个参数:
例如:
BinaryOperator<ArrayList<Integer>> combiner = (x, y) -> { x.addAll(y); return x; };
BiFunction<ArrayList<Integer>, Integer, ArrayList<Integer>> accumulator = (x, y) -> {
if (y % 2 == 0) {
x.add(y);
}
return x;
};
List<Integer> list = Stream.of(1, 2, 3, 5, 6, 8, 9, 10).reduce(new ArrayList<Integer>(),
accumulator,
combiner);
System.out.println(list);
请注意,此解决方案可能不适用于并行Streams。此外,它更容易坚持.filter()
方法,因此我强烈建议您这样做。