BAERUS
BAERUS

Reputation: 4319

java 8 use streams in a "forky" way

I am curious, if it is somehow possible, to not always go just straight within a stream. Imagine this sample code:

List<Employee> employees = [...];

employees.stream()
    .map(Employee::getCity)
    .map(City::getCountry)
    .map(countryService::determineHazardLevel)
    .filter(level -> level > 5) // integer
    // this line not possible anymore as I drifted away from my employees ...
    .forEach(employee -> employee.setPriority(HIGH))

I iterate over a list of employees and want them to set a priority flag if they live in a city which is in a country with a certain hazard level of 5 or higher.

I'd love to go the stream way as above, but can't find a way to do it. I "am not allowed" to stream my way down the city, country, hazardlevel and possible further, as ultimatively I need my employee object I began with, to set the flag on him.

I only know Java, so I don't even know if this would actually be possible in other, possibly more functional, programming languages.

I could use the following code as a workaround, but it would be nicer to a cleaner way:

List<Employee> employees = [...];

employees.stream()
    .forEach(employee -> {
        Optional<Integer> lvl = Optional.of(employee)
            .map(Employee::getCity)
            .map(City::getCountry)
            .map(countryService::determineHazardLevel)
            .filter(level -> level > 5); // integer

        lvl.ifPresent(employee.setPriority(HIGH));
    }

Maybe I just got it all just wrong and need to look at it completely different ...

PS: I just wrote this stuff in notepad, not sure if I made some mistakes but I hope the idea comes around. Simply put, I see it like this: Normal streams are commands like A, B, C, D. But what I want to do is A, B, B1, B2, B3, C, D. But after going down the B road, I can't go back on my "main stream".

Upvotes: 3

Views: 724

Answers (2)

Holger
Holger

Reputation: 298559

The simplest solution is to chain method calls, just like in Kayaman’s answer.

employees.stream()
    .filter( employee -> employee.getCity().getCountry().determineHazardLevel() > 5).
    .forEach(employee -> employee.setPriority(HIGH))

Alternatively, you can use the stream steps in an inner operation:

employees.stream()
    .filter( employee -> Stream.of(employee)
                               .map(Employee::getCity)
                               .map(City::getCountry)
                               .mapToInt(countryService::determineHazardLevel)
                               .anyMatch(level -> level > 5))
    .forEach(employee -> employee.setPriority(HIGH))

But for a simple chain of map steps, I’d stay with a chain of ordinary method invocations.

Upvotes: 7

Kayaman
Kayaman

Reputation: 73578

No, as the stream is changing from Stream<Employee> to Stream<Integer> through the map() operations (after all, that's what map() is supposed to do, and there's no unmap()).

You could only do it with

employees.stream().
    filter(e -> e.getCity().getCountry().determineHazardLevel() > 5).
    forEach(...)

which is ugly, but keeps the original Stream<Employee>. For "less ugly" code, implement determineHazardLevel() in Employee as well.

Upvotes: 4

Related Questions