使用JavaStream
API时看到的缺点之一是,与迭代版本相比,该代码似乎可读性较差。封装通常可以提高代码的可读性,因此我正在寻找封装Java Stream
操作的最佳方法。例如,这是简单的一系列Stream
操作,以典型方式实现(无封装):
void method1() {
List<Integer> result = IntStream.range(1, 10)
// Two Stream "intermediate" operations:
.filter(i -> i % 2 != 0).map(i -> i * 2)
.boxed().collect(Collectors.toList());
log.debug("Result: {}", result);
// Result: [2, 6, 10, 14, 18]
}
这是我通过添加filterOutEvenNumbersAndMultiplyByTwo
方法实现封装的第一个简单尝试:
IntStream filterOutEvenNumbersAndMultiplyByTwo(IntStream stream) {
return stream.filter(i -> i % 2 != 0).map(i -> i * 2);
}
void method2() {
List<Integer> result = filterOutEvenNumbersAndMultiplyByTwo(IntStream.range(1, 10))
.boxed().collect(Collectors.toList());
log.debug("Result: {}", result);
// Result: [2, 6, 10, 14, 18]
}
您可以看到,我在一个新方法中封装了两个中间Stream
操作,在这种情况下似乎没有多大意义,但这只是一个示例,可能有两个以上Stream
操作,并且更复杂的。新方法提高了可读性,并且可以进行单元测试。上面的代码可以工作,但是看起来不是很漂亮或干净,理想情况下,我希望能够写一些东西:]
List<Integer> result = IntStream.range(1, 10)
// This obviously does not compile
.filterOutEvenNumbersAndMultiplyByTwo()
.boxed().collect(Collectors.toList());
我想可以做到,但是需要大量的精力,因为我必须实现Stream
接口...还有另一种方法吗?也许我可以使用一个图书馆?也许我的面向对象的思想正在试图对并非本意的东西进行封装,但我仍然想知道是否有可能。
filterOutEvenNumbers
只是一个谓词。multiplyByTwo
是映射操作。
// we can unit test these
IntPredicate filterOutEvenNumbers = i -> i % 2 != 0
IntUnaryOperator multiplyByTwo = i -> i * 2;
您可以有N个谓词/映射操作。我们还可以在此处切换各种谓词/映射操作。
IntStream.range(1, 10)
.filter(filterOutEvenNumbers)
.map(multiplyByTwo)
.boxed()
.collect(Collectors.toList());