Краткий способ составления ссылок на методы 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");
не сможет скомпилировать