简体   繁体   中英

I'm told to convert a lambda with a parameterized constructor to a method reference

Lets say I have a class Gizmo with a constructor that takes a String. Lets say I want to convert a List<String> to a List<Gizmo> .

I might write:

List<String> strings = new ArrayList<>();
List<Gizmo> gizmos = strings
        .stream()
        .map(str -> new Gizmo(str))
        .collect(Collectors.toList());

Now, the problem is that I'm told by IntelliJ that I can replace the lambda with a method reference. Thing is, I'm pretty sure method references can't take parameters.

I think InteliJ means replacing

.map(str -> new Gizmo(str))

with

.map(Gizmo::new)

which is a constructor reference. See detailed explanation here .

Now, the problem is that I'm told by IntelliJ that I can replace the lambda with a method reference.

it simply means you can change this:

.map(str -> new Gizmo(str))

to this:

.map(Gizmo::new)

you can read more about Constructor method reference .

There is also a slight optimization when using a method reference instead of a lambda expression also.

Lambda expressions are de-sugared to static/instance method (depends if it's really a lambda/clojure ), but method references are not.

In your case when using a lambda expression ( t -> new Gizmo(t) ) compiler will generate an extra method in your class; that would look like this:

  private static Gizmo lambda$main$0(String s) {
      return new Gizmo(s);   
  }

In case of a method reference (constructor reference) it will not be present.

A method reference is just that: a reference to a method, no matter how many arguments the method actually has. A reference to a constructor is just a special case of method reference that references a constructor.

Suppose you have a Person class:

public class Person {

    private String name;
    private int age;

    public Person(String name, int age) {
        this.name = name;
        this.age  age;
    }

    // getters, setters
}

Now also suppose you have a BiFunction<String, Integer, Person> that maps name and age arguments to instances of the Person class:

BiFunction<String, Integer, Person> personCreator = 
    (String name, Integer age) -> new Person(name, age);

Or, as the types of the parameter of a lambda expression are directly inferred by the compiler:

BiFunction<String, Integer, Person> personCreator = (name, age) -> new Person(name, age);

You can use this 2-arg function as follows:

Person joe = personCreator.apply("Joe", 25);

Now, did you notice that the type and order of the parameters in the (name, age) lambda expression match those in the constructor? This means we might use a method reference instead:

BiFunction<String, Integer, Person> personCreator = Person::new;

And it will work, as expected:

Person jane = personCreator.apply("Jane", 23);

This is just to show you that the number of arguments doesn't matter when using method references. All that needs to match is the signature of the only one abstract method of a functional interface (in this case BiFunction.apply ) with the signature of the constructor.

If you want to further read about method references, go to the section about method references in the Java Tutorial.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM