I'm working with Twitter4J. But the question I'm asking is more general. I want to access the user id of a given tweet. Currently, I have the following two options:
//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);
I don't like the lambda expression in the first option, nor being forced to call two maps
in the second one. Is there a way to make a chain of method references? I know that Status::getUser::getId
does not work, but am wondering if there is an alternative.
Nope, these are the two ways of doing it. Anything else would end up being only less clear.
But, since you asked, here are some options.
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))
Or
static<T,R> Function<T,R> func(Function<T,R> f) {
return f;
}
stream.map(func(Status::getUser).andThen(User::getId))
Of the two options proposed, I tend to use the second, chaining calls to map()
.
There are other options, which uses built-in API instead of helper methods, as shown here. With the Function.compose()
or Function.andThen()
methods, you can chain function invocations. Predicate
and other functional interfaces implement similar default methods.
stream.map(((Function<Status, User>) Status::getUser).andThen(User::getId))
.forEach(System.out::println);
Alternatively
Function<Status, User> toUser = Status::getUser;
stream.map(toUser.andThen(User::getId)).forEach(System.out::println);
The drawback is that, in order to use these, the functional interface type has to be given explicitly. That requires a cast or an assignment, and that looks a bit ugly. So for a mapping chain, I usually use multiple map()
calls.