17

I want to use a method reference based off another method reference. It's kind of hard to explain, so I'll give you an example:

Person.java

public class Person{
    Person sibling;
    int age;

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

    public void setSibling(Person p){
        this.sibling = p;
    }

    public Person getSibling(){
        return sibling;
    }

    public int getAge(){
        return age;
    }
}

Given a list of Persons, I want to use method references to get a list of their sibling's ages. I know this can be done like this:

roster.stream().map(p -> p.getSibling().getAge()).collect(Collectors.toList());

But I'm wondering if it's possible to do it more like this:

roster.stream().map(Person::getSibling::getAge).collect(Collectors.toList());

It's not terribly useful in this example, I just want to know what's possible.

ewok
  • 20,148
  • 51
  • 149
  • 254
  • 6
    [Chain of Map method references](http://stackoverflow.com/questions/26920866/chain-of-map-method-references) – rgettman Mar 24 '16 at 17:06

3 Answers3

15

You need to use two map operations in that case:

roster.stream().map(Person::getSibling).map(Person::getAge).collect(Collectors.toList());

The first one maps the Person to its sibling and the second one maps the Person to its age.

Tunaki
  • 132,869
  • 46
  • 340
  • 423
2

You can use Functions.chain() from Eclipse Collections to chain method references:

MutableList<Person> roster = Lists.mutable.empty();
MutableList<Integer> ages = 
    roster.collect(Functions.chain(Person::getSibling, Person::getAge));

If you can’t change roster from List

List<Person> roster = Lists.mutable.empty();
List<Integer> ages =
    ListAdapter.adapt(roster).collect(Functions.chain(Person::getSibling, Person::getAge));

Since age is an int, you can avoid boxing by using an IntList:

MutableList<Person> roster = Lists.mutable.empty();
IntList ages = roster.collectInt(Functions.chainInt(Person::getSibling, Person::getAge));

Note: I am a contributor to Eclipse Collections.

Nikhil Nanivadekar
  • 1,152
  • 11
  • 10
2

Use Function.andThen, and possibly wrap your first method reference in a call, or cast.

public static <V, R> Function<V,R> ofFunction(Function<V,R> function) {
    return function;
}

roster.collect(ofFunction(Person::getSibling).andThen(Person::getAge));
aholt
  • 2,829
  • 2
  • 10
  • 13