Ссылки метода цепочки карт
Я работаю с Twitter4J. Но вопрос, который я задаю, более общий. Я хочу получить доступ к идентификатору пользователя данного твита. В настоящее время у меня есть следующие два варианта:
//Option 1
stream.map(status -> status.getUser().getId())
.forEach(System.out::println);
//Option 2:
stream.map(Status::getUser)
.map(User:getId)
.forEach(System.out::println);
Мне не нравится выражение лямбда в первом варианте, а также не требуется вызывать два maps
во втором. Есть ли способ сделать цепочку ссылок на методы? Я знаю, что Status::getUser::getId
не работает, но мне интересно, есть ли альтернатива.
Ответы
Ответ 1
Нет, это два способа сделать это. Все остальное будет менее ясным.
Но, поскольку вы спросили, вот несколько вариантов.
static<T,U,R> Function<T,R> chain(
Function<? super T, ? extends U> f1,
Function<? super U, ? extends R> f2) {
return t -> f2.apply(f1.apply(t));
}
stream.map(chain(Status::getUser, User::getId))
или
static<T,R> Function<T,R> func(Function<T,R> f) {
return f;
}
stream.map(func(Status::getUser).andThen(User::getId))
Ответ 2
Из двух предложенных вариантов я предпочитаю использовать второй вызов цепочки для map()
.
Существуют и другие варианты, которые используют встроенный API вместо вспомогательных методов, как показано здесь. Function.compose()
или Function.andThen()
, вы можете цеплять вызовы функций. Predicate
и другие функциональные интерфейсы реализуют аналогичные методы по умолчанию.
stream.map(((Function<Status, User>) Status::getUser).andThen(User::getId))
.forEach(System.out::println);
В качестве альтернативы
Function<Status, User> toUser = Status::getUser;
stream.map(toUser.andThen(User::getId)).forEach(System.out::println);
Недостатком является то, что для их использования тип функционального интерфейса должен быть указан явно. Для этого требуется бросок или задание, и это выглядит немного уродливо. Поэтому для цепи отображения я обычно использую несколько вызовов map()
.