Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Concise way of composing Java method references?

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...)

like image 807
Gene Avatar asked Aug 18 '17 15:08

Gene


People also ask

What is static method reference in Java?

A static method reference refers to a static method in a specific class. Its syntax is className::staticMethodName , where className identifies the class and staticMethodName identifies the static method. An example is Integer::bitCount .

Why method reference is used?

A method reference is an alternative to creating an instance of a reference type. Among several other uses, method references can be used to create a functional interface instance (that is, an instance of a functional interface type).

Is method references help to point to methods by their names?

In those cases, it's often clearer to refer to the existing method by name. Method references enable you to do this; they are compact, easy-to-read lambda expressions for methods that already have a name.


1 Answers

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);
like image 197
Andrew Tobilko Avatar answered Oct 14 '22 17:10

Andrew Tobilko