3

I have an object (Adult) with another object (Child) as a parameter. I am trying to write a Function that will return the child's name if given the adult.

I wrote this:

public static void main(String[] args) {
    Function<Adult, Object> adult_name_f = Adult::getName;
    Function<Adult, Object> adult_child_f = Adult::getChild;
    Function<Adult, Object> child_name_f = Adult::getChild.getName;
}

static class Adult {
    String name;
    Child child;

    public Child getChild() {
        return child;
    }

    public String getName() {
        return name;
    }
}

static class Child {
    String name;

    public String getName() {
        return name;
    }
}

but (obviously) Adult::getChild.getName is not a valid Function.

Is there a way to return the name of the child if given the adult?

ryvantage
  • 13,064
  • 15
  • 63
  • 112

2 Answers2

5

First, you should specify the appropriate return type of the Function.

Function<Adult, String> adult_name_f = Adult::getName;
Function<Adult, Child> adult_child_f = Adult::getChild;

You can then use the Function.andThen() method to create the third Function.

Function<Adult, String> child_name_f = adult_child_f.andThen(Child::getName);

Alternatively, and more commonly done, to make a method chain, you can define the Function using a lambda expression. You can even use lambda expressions for the first two, but method reference is better (less generated code).

Function<Adult, String> adult_name_f = a -> a.getName();
Function<Adult, Child> adult_child_f = a -> a.getChild();
Function<Adult, String> child_name_f = a -> a.getChild().getName();

Test

Adult mary = new Adult("Mary", new Child("Jesus"));
System.out.println(adult_name_f.apply(mary));  // prints: Mary
System.out.println(adult_child_f.apply(mary)); // prints: Test$Child@XXXXXXXX
System.out.println(child_name_f.apply(mary));  // prints: Jesus
Andreas
  • 154,647
  • 11
  • 152
  • 247
  • Great answer. In my 'XY Problem', the functions are in a `List` and are iterated over. So I can't specify a proper return type. Either way, your answer solves the problem. – ryvantage Mar 28 '17 at 11:30
4

The simplest way is just to use a lambda.

Function<Adult, Object> child_name_f = adult -> adult.getChild().getName();

Note that this is the syntax of what Java calls a "lambda". The syntax you used in your question is a method reference, not a lambda, but the two are closely related. A method reference can always be expressed as a lambda. Thus:

Function<Adult, Object> adult_name_f = Adult::getName;

is equivalent to

Function<Adult, Object> adult_name_f = adult -> adult.getName();

[There may be differences in how they're implemented, but the effect is the same for all practical purposes.]

When you want to call two methods, there's no simple way to do this with method reference syntax, but a lambda works just fine.

See How to do function composition? for some other ideas of how you can create a function composition from two method references. I think those answers are interesting, but in real life I'd still use the lambda.

Community
  • 1
  • 1
ajb
  • 31,309
  • 3
  • 58
  • 84