patternjavaMinor
Printing removed items using lambdas and streams
Viewed 0 times
lambdasremoveditemsprintingusingstreamsand
Problem
I'm struggling to make my lambdas readable.
I've seen various approaches. Below are three different examples that all do the same thing.
Forgive the example: I suspect there are better actual solutions to this problem. I'm only concerned with readability (and ultimately supportability).
Personally, I find the lambda approaches more difficult to read than the simple for-loop: they make me think too much, which detracts from the readability. So this is stopping me from using them in actual production code.
The more complex the operation, the worse my lambdas seem to look!
Does anyone have any tips to make my lambdas more readable?
Or.. do people from a functional programming background actually find the lambdas above easier to read than the loop?
I've seen various approaches. Below are three different examples that all do the same thing.
Forgive the example: I suspect there are better actual solutions to this problem. I'm only concerned with readability (and ultimately supportability).
/** Output any items that are present in "existing" but not in "updated" */
private static void outputRemovedItems(List existing, List updated) {
// #1 simple for-loop
for (String item : existing) {
if (!updated.contains(item)) {
System.out.println("item " + item + " removed");
}
}
// #2 fluid lambdas
existing.stream()
.filter(item -> !updated.contains(item))
.forEach(item -> System.out.println("item " + item + " removed"));
// #3 awful-looking middle-ground: functions split out
Predicate onlyRemovedItems = item -> !updated.contains(item);
Consumer outputItems = item -> System.out.println("item " + item + " removed");
existing.stream().filter(onlyRemovedItems).forEach(outputItems);
}Personally, I find the lambda approaches more difficult to read than the simple for-loop: they make me think too much, which detracts from the readability. So this is stopping me from using them in actual production code.
The more complex the operation, the worse my lambdas seem to look!
Does anyone have any tips to make my lambdas more readable?
Or.. do people from a functional programming background actually find the lambdas above easier to read than the loop?
Solution
Your "fluid" example is fine, well structured, the newlines are consistent, and is in line with code styles that I have seen and like. It is perhaps a bit too soon to say it follows "best practice", but it does look right.
The "middle-ground" approach you have is immediately "identical" to the fluid approach, but in this context is less readable, even if functionally identical. It does have advantages when your function is, for example, a method parameter, or an injected constant (like a custom comparator, or something). Since the code is all localized to a single method, though, the need to separate the declaration and use of the function is simply not there.
My only concern with your fluid approach, and it is a small one, is that you reuse the
Additionally, using
One lase comment, I have found that the more I use Java 8 features the easier it gets to establish the right mindset when reading the code. You may just find that it grows on you, and your statement "I find the lambda approaches more difficult to read than the simple for-loop" is no longer true. Also, consider this:
and consider doing that in "the simple for loop".
// #2 fluid lambdas
existing.stream()
.filter(item -> !updated.contains(item))
.forEach(item -> System.out.println("item " + item + " removed"));The "middle-ground" approach you have is immediately "identical" to the fluid approach, but in this context is less readable, even if functionally identical. It does have advantages when your function is, for example, a method parameter, or an injected constant (like a custom comparator, or something). Since the code is all localized to a single method, though, the need to separate the declaration and use of the function is simply not there.
My only concern with your fluid approach, and it is a small one, is that you reuse the
item placeholder in two contexts. While it is logical, in this case, to use item, I find it is typically better to have unique variable names at each stage in the pipeline, perhaps:// #2 fluid lambdas
existing.stream()
.filter(item -> !updated.contains(item))
.forEach(removed -> System.out.println("item " + removed + " removed"));Additionally, using
printf helps too:.forEach(removed -> System.out.printf("item %s removed\n", removed));One lase comment, I have found that the more I use Java 8 features the easier it gets to establish the right mindset when reading the code. You may just find that it grows on you, and your statement "I find the lambda approaches more difficult to read than the simple for-loop" is no longer true. Also, consider this:
// #2 fluid lambdas
existing.stream()
.parallel()
.filter(item -> !updated.contains(item))
.forEach(removed -> System.out.printf("item %s removed\n", removed));and consider doing that in "the simple for loop".
Code Snippets
// #2 fluid lambdas
existing.stream()
.filter(item -> !updated.contains(item))
.forEach(item -> System.out.println("item " + item + " removed"));// #2 fluid lambdas
existing.stream()
.filter(item -> !updated.contains(item))
.forEach(removed -> System.out.println("item " + removed + " removed"));.forEach(removed -> System.out.printf("item %s removed\n", removed));// #2 fluid lambdas
existing.stream()
.parallel()
.filter(item -> !updated.contains(item))
.forEach(removed -> System.out.printf("item %s removed\n", removed));Context
StackExchange Code Review Q#84964, answer score: 6
Revisions (0)
No revisions yet.