36

While rather impatiently waiting for Java 8 release and after reading brilliant 'State of the Lambda' article from Brian Goetz I noticed that function composition was not covered at all.

As per above article, in Java 8 the following should be possible:

// having classes Address and Person
public class Address {

    private String country;

    public String getCountry() {
        return country;
    }
}

public class Person {

    private Address address;

    public Address getAddress() {
        return address;
    }
}

// we should be able to reference their methods like
Function<Person, Address> personToAddress = Person::getAddress;
Function<Address, String> addressToCountry = Address::getCountry;

Now if I would like to compose these two functions to have a function mapping Person to country, how can I achieve this in Java 8?

gvlasov
  • 18,638
  • 21
  • 74
  • 110
Yuriy Nakonechnyy
  • 3,742
  • 4
  • 29
  • 41

2 Answers2

57

There are default interface functions Function::andThen and Function::compose:

Function<Person, String> toCountry = personToAddress.andThen(addressToCountry);
Yassin Hajaj
  • 21,337
  • 9
  • 51
  • 89
Andrey Chaschev
  • 16,160
  • 5
  • 51
  • 68
22

There is one flaw in using compose and andThen. You have to have explicit variables, so you can't use method references like this:

(Person::getAddress).andThen(Address::getCountry)

It won't be compiled. What a pity!

But you can define an utility function and use it happily:

public static <A, B, C> Function<A, C> compose(Function<A, B> f1, Function<B, C> f2) {
        return f1.andThen(f2);
    }

compose(Person::getAddress, Address::getCountry)
Mikhail Golubtsov
  • 6,285
  • 3
  • 29
  • 36
  • 4
    Good point - it's really a pity that it doesn't work this way :) However it's possible to invoke `andThen` method by using explicit cast on first method reference: `((Function) Person::getAddress).andThen(Address:getCountry)` - still looks ugly, but it's a one-liner already. Please also note that type of second method reference it deducted automatically so no need for explicit cast – Yuriy Nakonechnyy Sep 29 '15 at 08:39
  • 6
    @Yura, guys, what's wrong with `Function fn = p -> p.getAddress().getCountry();`? It's shorter than using this invented `compose` or even not working `(Person::getAddress).andThen(Address::getCountry)` – Tagir Valeev Sep 29 '15 at 08:59
  • 2
    @TagirValeev yes - you're right, that's another simple solution to mentioned problem :) However to me, `andThen` and `compose` are more interesting from the functional programming point of view – Yuriy Nakonechnyy Sep 29 '15 at 09:57
  • 2
    `compose` in this answer uses order of application of functions reversed from traditional: https://en.wikipedia.org/wiki/Function_composition – andrybak Jan 17 '17 at 10:09