使用JavaStream
API时看到的缺点之一是,与迭代版本相比,该代码似乎可读性较差。
顺便说一句,这就是我的想法,但是我只是给出一些上下文(以避免the XY problem),我要问的是与此无关的,因此希望这将not被认为是基于意见问题。
封装通常可以提高代码的可读性(再次,仅给出给定的上下文),因此我正在寻找封装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
操作,并且更复杂的。
新方法提高了可读性(IMHO),并且可以进行单元测试(这是事实)。上面的代码可以工作,但是看起来不是很漂亮或干净,理想情况下,我希望能够写一些东西:]
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());