Difference between normal instantiation and instantiation including method reference

Viewed 186

Why is in the first case SomeClass only instantiated once, but in the second case n-times, where n is the number of elements in the stream?

List<SomeClass> list = stream.map(new SomeClass()::method)
                            .collect(Collectors.toList());

List<SomeClass> list = stream.map(a -> {return new SomeClass().method(a);})
                            .collect(Collectors.toList());

The method "method" in this case return the object itself (= return this).

So in the first case the list contains only one object, but n-times. In the second case the list contains n-different objects.

For reproducing the issue: main:

Arrays.asList(true, false, true, false).stream().map(new SomeClass()::method)
                                                .collect(Collectors.toList());

System.out.println("----------------------");
        
Arrays.asList(true, false, true, false).stream().map(a -> {return new SomeClass().method(a);})
                .collect(Collectors.toList());

and SomeClass.java:

public class SomeClass {
    
    public SomeClass() {
        System.out.println(this);
    }
    
    public SomeClass method(Boolean b) {
        return this;
    }
}
2 Answers

Method references only comes in four kinds (See "Kinds of method references" in this page):

  • References to a static method
  • References to an instance method of a particular object
  • Reference to an instance method of an arbitrary object of a particular type
  • Reference to a constructor

There isn't a kind of method reference that "creates a new object every time", whatever that means. new SomeClass()::methodName is of the second kind. It refers to the method methodName of one particular object. That object is a newly created SomeClass object. It doesn't create any more SomeClass objects when the method is called, because it is a reference to someMethod of that particular SomeClass object that you newly created.

The lambda expression, on the other hand, creates a new SomeClass every time it is called, because new SomeClass() is inside the { ... }.

Because in the first snippet you invoke new SomeClass() only once, because this:

List<SomeClass> list = stream.map(new SomeClass()::method)
                             .collect(Collectors.toList());

Is effectively equal to this:

SomeClass s = new SomeClass();
List<SomeClass> list = stream.map(a -> s.method(a))
                             .collect(Collectors.toList());

You invoke the method method() on the instance s, in the first snippet this instance is just not saved into a variable, but used directly

Related