One of the drawbacks which I see when using the Java Stream
API is that the code seems less readable when compared to its iterative version.
By the way, that is what I think, but I am just giving some context (to avoid the XY problem), what I am going to ask is independent of that, so hopefully this will not be considered an opinion based question.
Encapsulation usually increases code readability (again, just given context) so I am looking for the best way to encapsulate Java Stream
operations.
For example, this is a simple series of Stream
operations implemented the typical way (no encapsulation):
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]
}
And this is my first and simple attempt to achieve encapsulation, by adding the filterOutEvenNumbersAndMultiplyByTwo
method:
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]
}
As you can see I have encapsulated two intermediate Stream
operations inside a new method, which does not seem to make much sense in this case but it is just an example, there could be more than two Stream
operations and also more complicated ones.
The new method increases readability (IMHO) and can be unit tested (that's a fact).
The code above works, but it does not look very nice or clean, ideally, I would like to be able to write something such as:
List<Integer> result = IntStream.range(1, 10)
// This obviously does not compile
.filterOutEvenNumbersAndMultiplyByTwo()
.boxed().collect(Collectors.toList());
I guess that it could be done but it would require significant effort since I would have to implement the Stream
interface...
Is there another way?
Maybe a library exists which I could use?
Maybe my OO mind is trying to force encapsulation on something that's not meant to but I still wonder if it is possible.
filterOutEvenNumbers
is simply a predicate.
multiplyByTwo
is a map operation.
// we can unit test these
IntPredicate filterOutEvenNumbers = i -> i % 2 != 0
IntUnaryOperator multiplyByTwo = i -> i * 2;
You can have N number of Predicates / map operations. We can also switch various predicates / map operations here.
IntStream.range(1, 10)
.filter(filterOutEvenNumbers)
.map(multiplyByTwo)
.boxed()
.collect(Collectors.toList());
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With