Java 8 stream map to new Objects

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 new SomeObject
  • 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 calling map
  • 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 method convertToSomeObject the created instance
    • returns the result of calling the convertToSomeObject method, that is, the newly created instance of the SomeObject class
  • 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 takes Item 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 accepts Item and returns SomeObject :

     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 the Item class:

     public SomeObject convertToSomeObject() { SomeObject object = new SomeObject(); object.name = this.getName(); return object; } list.stream().map(Item::convertToSomeObject)
Scroll to Top