Map a single object using Stream

letthefireflieslive :

Is this a good use case of java 8's Stream:

final Car carWithInterior = Stream.of(carWithEngine)
            .map(car -> installSeats.execute(car))
            .map(car -> installDashBoard.execute(car))
            .map(car -> installSunRoof.execute(car))
            .collect(car);

carWithEngine is a Car. Note that sometimes even if the car (w/ dashboard) is pass to the installSunroof, it will not do any since there's no hole in the roof. I should always get a car at the end of the installation/mapping process.

The installation sequence is required (that's why I thought of streaming it) and next installation may sometimes need a parameter from the pass car instance to perform it's operation.

  1. Is this a good use case for java 8's Stream?

  2. Obvioulsy, my collect at the end is not right. How should I get the car at the end of this installation/assembly line? findFirst().get() will work but I think that's bad, since I should always get a car at the end even if the installation didn't do anything with the carWitEngine and I'm not stream multiple elements.

I'm not sure how cars are assembled but let say you need to put the engine first before adding the interiors for the sake of this analogy

shinjw :

Since you're looking to perform operations on a single object. Java 8 Optional would be appropriate.

The builder pattern (Phil C's comment) is definitely worth visiting if each of these map operations are simply hydrating the Car object.

  1. Tapping open a stream for a single object is not a good use case for streams.
  2. You're venturing into dangerous territory (side-effecty) if the Car gets dropped in the stream through a .map() operation. When dealing with Streams it is highly recommended to use these operations the way they are intended. If you plan on dropping an element from a stream .filter()

Edit to OP's edits:

There is some fundamental confusion around "sequence" and how that that translates

Optional

 car => map(execute) => map(execute) => transformedcar

Streams

[car1, car2, car3]
     => map(execute) => map(execute) => updatedcar1                |  => findFirst (Optional<Car>)
           => map(execute) => map(execute) =>  updatedcar2         |
                 => map(execute) => map(execute) => updatedcar3    |
                                                                collect
                                                 [updatedcar1, updatedcar2, updatedcar3]

The findFirst method will return an Optional. The collect method will provide a terminal operation that lets you aggregate/reduce/group these results.

These map operations transform the passed elements "sequentially". But a Stream would be appropriate cases where you must deal with many or "sequence of" cars.

To revisit #2

You have the option of providing an alternative with Optional with orElse(car).

But this is where you have to be contentious of the side effects you are performing.

If the execute method is manipulating and returning the same object that was passed into it, there will be unintended consequences. I'll be using Optionals for example but same will apply for Streams.

private final Car car Optional.of(carWithEngine)
   .map(installSunroof.execute)   // <-- updatedCarWithSunroof
   .map(installDashboard.execute) // <-- updatedCarWithSunroofAndDashboard
   .orElse(carWithEngine)         // <-- updatedCarWithSunroofAndDashboard

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=86438&siteId=1
Recommended