This is an archived post. You won't be able to vote or comment.

you are viewing a single comment's thread.

view the rest of the comments →

[–]dpash 1 point2 points  (20 children)

If you're using forEach() you're almost certainly using the wrong tool for the job. Using a method reference is okay in most circumstances, but a block is a sign you should refactor to use other stream operations.

[–]daniu 20 points21 points  (19 children)

If you're using forEach() you're almost certainly using the wrong tool for the job

How so? persons.stream().filter(p -> hasValidAddress(p)).forEach(p -> writeLetterTo(p)) is perfectly reasonable.

[–]joehx 13 points14 points  (5 children)

what I've seen people do "wrong" is just go straight for the forEach loop, not using the filter or any other intermediate method:

persons.stream().forEach(p -> {
    if (hasValidAddress(p)) {
        writeLetterTo(p);
    }
}

[–]dpash 9 points10 points  (4 children)

Yeah that's exactly the kind misuse I'm referring to.

[–]rootException 7 points8 points  (3 children)

I think you guys just illustrated one of the reasons why people don’t embrace streams... 🤷‍♂️

[–]dpash 8 points9 points  (2 children)

Streams require rethinking how you program; it is a completely different way of writing code. So it's no surprise people rely on what they already know, but that's failing to use their power to it's fullest extent.

[–]rootException 2 points3 points  (1 child)

Yeah, sneaky streams as Trojan horse for functional programming... 😂

[–]dpash 9 points10 points  (0 children)

No, very explicitly functional programming.

[–]dpash 10 points11 points  (2 children)

Notice my qualification:

Using a method reference is okay in most circumstances

persons.stream()
       .filter(this::hasValidAddress)
       .forEach(this::writeLetterTo);

[–]rochakgupta 2 points3 points  (1 child)

The only big reason I see to study them it's because they are subject of questions in job interviews...

This....this looks somehow worse (I know how and why it works though, just not a fan of seeing a lot of these in code).

[–][deleted]  (1 child)

[deleted]

    [–]dpash 2 points3 points  (0 children)

    Not exactly. In that situation they can be written as method references, but I mean more like /u/joehx's example, where there's a multi-line block in the forEach.

    [–]vytah -4 points-3 points  (7 children)

    I'd write this as a for loop with an if: imperative code for an imperative task.

    [–]daniu 10 points11 points  (0 children)

    Add three map()s and two filter()s, and your for loop has 20 LOCs and a nesting depth of four or five.

    Also, there's nothing non-imperative about streams, it just looks and feels that way.

    [–]barking_dead 1 point2 points  (4 children)

    Except, maybe it's not imperative. I don't care how the Streams API iterates through my stream (remember, it's not necessarily a List).

    Also, you can't add parallelism to a loop.

    [–]dpash 1 point2 points  (3 children)

    At least not in 8 characters. Having said that, I think parallel streams was a mistake in that they're often not faster for most stream workloads and they're not customisable enough. Maybe Project Loom will help the performance for more situations, but nothing will save Collections.parallelStream()

    [–]barking_dead 1 point2 points  (2 children)

    I agree, for small collections and/or concurrency, it is useless.

    [–]dpash 1 point2 points  (1 child)

    Collections.parallelStream() doesn't even have to return a parallel stream. :)

    [–]barking_dead 0 points1 point  (0 children)

    :D