11

Given some Java 8 method functions:

class Foo { Bar getBar() {} }
class Bar { Baz getBaz() {} }

A composition of the two accessors looks like:

Function<Foo, Bar> getBarFromFoo = Foo::getBar;
Function<Bar, Baz> getBazFromBar = Bar::getBaz;
Function<Foo, Baz> getBazFromFoo = getBarFromFoo.andThen(getBazFromBar);

Is there a more concise way? This seems to work

((Function<Foo, Bar>) Foo::getBar).andThen(Bar::getBaz)

But it's rather ugly. The outer parens make sense for precedence reasons, but why is the cast necessary?

(Foo::getBar::getBaz would be nice, but alas...)

5
  • Why not do foo -> foo.getBar()::getBaz? Seems like you're overcomplicating it. Is there something I'm missing? Commented Aug 18, 2017 at 16:07
  • 2
    @VinceEmigh, did you mean foo -> foo.getBar().getBaz()? otherwise, it makes no sense Commented Aug 18, 2017 at 16:10
  • @VinceEmigh, the way you suggested is not flexible enough. It is much better to prepare simple mappers (a->b, b->c) composing them with simple operations like Function's compose, andThen at runtime rather than building up all possible cases at compile time. Commented Aug 18, 2017 at 16:20
  • @AndrewTobilko You could use currying if flexibility is a concern: foo -> bar -> bar::getBaz Commented Aug 18, 2017 at 16:28
  • @VinceEmigh, you can't use foo -> bar -> bar::getBaz to achieve a map series (here, to get a Baz as output). It could return sth like Function<Foo, Function<Bar, Function<Bar, Baz>>> which doesn't make sense Commented Aug 18, 2017 at 16:36

5 Answers 5

10

Let's define a functional interface:

@FunctionalInterface
interface MyFunctionalInterface {
    Bar getBar(Foo f);
}

We can simplify the method reference Foo::getBar a bit,

(Foo foo) -> foo.getBar();

which means "take a Foo and return a Bar". For that description, a lot of methods are suitable (for instance, our interface with the getBar and a Funtion<Foo, Bar> with its apply):

MyFunctionalInterface f1 = (Foo foo) -> foo.getBar();
Function<Foo, Bar> f2 = (Foo foo) -> foo.getBar();

That is the answer to the question why the cast is necessary.


To answer the question whether there is a more concise way affirmatively, we have to set a context. The context unambiguously gives us a Function to continue working with:

class Functions {
    public static <I, O> Function<I, O> of(Function<I, O> function) {
        return function;
    }
}

Functions.of(Foo::getBar).andThen(Bar::getBaz);
Sign up to request clarification or add additional context in comments.

Comments

4

There is no dedicated way of composing functions in Java other than andThen().

You need to perform the cast because Foo::getBar is ambiguous. **It could match every interface having similar method signature.

Unfortunately, ((Function<Foo, Bar>) Foo::getBar).andThen(Bar::getBaz) is the best you can do.

Comments

1

Maybe just use a lambda expression?

x -> x.getBar().getBaz()

There is no other way to compose functions other than what you already suggested because of type ambiguity. This is not even much longer than Foo::getBar::getBaz

Comments

0

That's the best you are going to get. If you think that this would work:

Foo::getBar::getBaz

it will not. That's because Foo::getBar is a poly expression - it depends on the context used - it could be a Function, but could also be a Predicate for example; so it could potentially apply to many things, so the cast is just necessary there.

You could hide that behind a method that would do the chaining and andThen, but the problem is still there.

EDIT

See an example here:

public static void cool(Predicate<Integer> predicate) {

}

public static void cool(Function<Integer, String> function) {

}

and the expression cool(i -> "Test"); will fail to compile

4 Comments

Thanks. I know it won't work. Just wishing... The type inferencer should know it's not a predicate because it doesn't return boolean. I'm not a Java type inference wizard, but it seems logical that since Foo::getBar satisfies any functional interface of the form Foo->Bar and getBaz satisfies Bar->Baz, then it seems reasonable that Foo::getBar::getBaz is a poly expression that satisfies any functional interface of the form Foo->Baz.
@Gene the Predicate and Function were just one example to prove that these are indeed poly expressions (see edit)... And type inference for lambdas and method references are not that obvious; that's the reason why probably this chaining was not implemented at all - it's by far not trivial
I've actually written a type inferencer. I know it's not trivial. That doesn't mean it's impossible.
@Gene I'm not saying it's impossible btw - it could be improved in some future idk version... just that at the moment, me personally, (and I am definitely not the right person for this), can't see a real way to do it safely.
0

With Guava, you can use Functions.compose:

import com.google.common.base.Functions;

...

Functions.compose(Bar::getBaz, Foo::getBar);

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.