Printing removed items using lambdas and streams
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.


// #2 fluid lambdas
existing.stream()
    .filter(item -&gt; !updated.contains(item))
    .forEach(item -&gt; 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 -&gt; !updated.contains(item))
    .forEach(removed -&gt; System.out.println("item " + removed + " removed"));


Additionally, using printf helps too:

    .forEach(removed -&gt; 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 -&gt; !updated.contains(item))
    .forEach(removed -&gt; System.out.printf("item %s removed\n", removed));


and consider doing that in "the simple for loop".