Question:
How can you map a stream to new objects? Or, are these examples not equivalent?
list.stream().map(new SomeObject()::convertToSomeObject)
list.stream().map(item -> new SomeObject().convertToSomeObject(item))
public SomeObject convertToSomeObject(Item item) {
this.name = item.getName;
this.value = item.getValue;
return this;
}
in the first case, everything was mapped with one object
Answer:
Why the first option doesn't work
When sewing
list.stream().map(new SomeObject()::convertToSomeObject)
the following happens:
- before calling the
map
method , a newSomeObject
- a reference to the method of this object is passed as a lambda parameter to the
map
method - all the elements of the old stream are taken in turn, the passed method is applied to them
- from the new objects obtained as a result of applying the method, a new stream is created
Here, the SomeObject
object is created exactly once, and since its convertToSomeObject
method always returns the only created instance, it turns out that the new stream consists of references to the same object. In this case, the convertToSomeObject
method was called for each stream element and each time the object field values were overwritten.
Why does the second variant work?
When sewing
list.stream().map(item -> new SomeObject().convertToSomeObject(item))
the following happens:
- no
SomeObject
before callingmap
- a lambda function is passed to the
map
method, which works like a regular function:- takes an
item
object - creates a new instance of the
SomeObject
class - calls the
convertToSomeObject
methodconvertToSomeObject
the created instance - returns the result of calling the
convertToSomeObject
method, that is, the newly created instance of theSomeObject
class
- takes an
- note that the lambda function creates a new object each time it is called
How to fix the first option
-
write a constructor for
SomeObject
that takesItem
as a parameter:public SomeObject(Item item) { this.name = item.getName(); } list.stream().map(SomeObject::new)
-
add a static method to the
SomeObject
class that acceptsItem
and returnsSomeObject
:public static SomeObject convertToSomeObject(Item item) { SomeObject object = new SomeObject(); object.name = item.getName(); return object; } list.stream().map(SomeObject::convertToSomeObject)
-
Move the
convertToSomeObject
method to theItem
class:public SomeObject convertToSomeObject() { SomeObject object = new SomeObject(); object.name = this.getName(); return object; } list.stream().map(Item::convertToSomeObject)