Краткий способ составления ссылок на методы Java?

Для некоторых функций метода Java 8:

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

Состав двух аксессуаров выглядит следующим образом:

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

Есть ли более сжатый способ? Кажется, это работает

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

Но это довольно уродливо. Внешние параны имеют смысл по причинам приоритета, но почему это необходимо?

(Foo::getBar::getBaz было бы неплохо, но, увы...)

Ответ 1

Определить функциональный интерфейс:

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

Мы можем немного упростить ссылку на метод Foo::getBar,

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

что означает "взять a Foo и вернуть a Bar". Для этого описания подходит множество методов (например, наш интерфейс с getBar и a Funtion<Foo, Bar> с его apply):

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

Это ответ на вопрос, почему актер нужен.


Чтобы ответить на вопрос, существует ли более сжатый способ утвердительно, мы должны установить контекст. Контекст недвусмысленно дает нам Function продолжить работу с:

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

Functions.of(Foo::getBar).andThen(Bar::getBaz);

Ответ 2

В Java нет специального способа компоновки функций, кроме andThen().

Вам нужно выполнить трансляцию, потому что Foo::getBar неоднозначно. ** Он может соответствовать любому интерфейсу, имеющему аналогичную сигнатуру метода.

К сожалению, ((Function<Foo, Bar>) Foo::getBar).andThen(Bar::getBaz) - лучшее, что вы можете сделать.

Ответ 3

Возможно, просто используйте выражение лямбда?

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

Нет другого способа компоновки функций, отличных от того, что вы уже предложили, из-за неоднозначности типа. Это не намного больше, чем Foo::getBar::getBaz

Ответ 4

Это лучшее, что вы получите. Если вы думаете, что это сработает:

Foo::getBar::getBaz

это не будет. Это потому, что Foo::getBar является поли выражением - оно зависит от используемого контекста - оно может быть Function, но может также быть Predicate, например; поэтому он может потенциально примениться ко многим вещам, поэтому актер просто необходим там.

Вы можете скрыть это за методом, который будет выполнять цепочку и andThen, но проблема все еще существует.

ИЗМЕНИТЬ

См. пример здесь:

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

}

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

}

и выражение cool(i -> "Test"); не сможет скомпилировать