4

Using a Java 8 lambda expression, I'm trying to do something like this.

List<NewObject> objs = ...;
for (OldObject oldObj : oldObjects) {
  NewObject obj = oldObj.toNewObject();
  obj.setOrange(true);
  objs.add(obj);
}

I wrote this code.

oldObjects.stream()
  .map(old -> old.toNewObject())
  .forEach({new.setOrange("true")})
  .collect(Collectors.toList()); 

This is invalid code because I'm then trying to do .collect() on what's returned by .forEach(), but forEach is void and does not return a list.

How should this be structured?

0

2 Answers 2

7

You can use Stream's peek method, which returns the Stream because it's an intermediate operation. It normally isn't supposed to have a side effect (it's supposed to be "non-interfering"), but in this case, I think the side effect (setOrange(true)) is intended and is fine.

List<NewObject> newObjects =
    oldObjects.stream()
        .map(OldObject::toNewObject)
        .peek( n -> n.setOrange(true))
        .collect(Collectors.toList());

It's about as verbose as your non-streams code, so you can choose which technique to use.

Sign up to request clarification or add additional context in comments.

3 Comments

There's a difference between side-effect-free and non-interfering. (Note that a void-returning lambda can only have side-effects, except for the trivial e -> {} consumer.) Determining that the lambda passed to peek actually is non-interfering is not always trivial (though what you've got here looks harmless enough.)
it's not more interfering than peek( n -> print(n) )
@bayou.io: this is not correct. Mutating a property of a stream element can be interfering, e.g. if the same element appears multiple times within the same stream. This is different to a print operation. But since oldObj.toNewObject() seems to create new instances we can conclude that this is not the case here. However, it still would be cleaner to construct the NewObject instance and set the orange property in one lambda within the map operation. Then, peek would be unnecessary.
5

You can use peek.

List<NewObject> list = oldObjects.stream()
                                 .map(OldObject::toNewObject)
                                 .peek(o -> o.setOrange(true))
                                 .collect(Collectors.toList());

Alternatively, you can mutate the elements after forming the list.

List<NewObject> list = oldObjects.stream()
                                 .map(OldObject::toNewObject)
                                 .collect(Collectors.toList());
list.forEach(o -> o.setOrange(true));

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.