Reputation: 4925
Is there an elegant way of using Guava to transform from a list of optionals to a list of present values?
For example, going from
ImmutableList.of(
Optional.of("Tom"), Optional.<String>absent(), Optional.of("Dick"),
Optional.of("Harry"), Optional.<String>absent()
)
to a list containing just
["Tom", "Dick", "Harry"]
One approach would be:
List<T> filterPresent(List<Optional<T>> inputs) {
return FluentIterable.from(inputs)
.filter(new Predicate<Optional<T>>() {
@Override
public boolean apply(Optional<T> optional) {
return optional.isPresent();
}
}).transform(new Function<Optional<T>, T>() {
@Override
public T apply(Optional<T> optional) {
return optional.get();
}
}).toList();
}
But this is verbose.
Java 8 is not an option, unfortunately.
Upvotes: 5
Views: 2867
Reputation: 28035
There's actualy built-in method for this in Guava: presentInstances
in Optional
:
Returns the value of each present instance from the supplied optionals, in order, skipping over occurrences of
absent()
. Iterators are unmodifiable and are evaluated lazily.
Example:
List<Optional<String>> optionalNames = ImmutableList.of(
Optional.of("Tom"), Optional.<String>absent(), Optional.of("Dick"),
Optional.of("Harry"), Optional.<String>absent());
Iterable<String> presentNames = Optional.presentInstances(optionalNames); // lazy
// copy to List if needed
List<String> presentNamesList = ImmutableList.copyOf(presentNames);
System.out.println(presentNamesList); // ["Tom", "Dick", "Harry"]
Upvotes: 15
Reputation: 9324
If you are calling a method in a loop which returns an Optional
and you want to create a List
of the returned values which are present, then you can use the toSet
method on the Optional
in conjunction with the addAll
method on the List
, like so:
List<String> strings = newArrayList();
for (Long id : ids) {
strings.addAll(getString(id).toSet());
}
This is useful if you want to return a List
, rather than an Iterable
, which you get from Optional.presentInstances
.
Upvotes: 0
Reputation: 20648
You could hide the predicate instances behind method calls to make the code more readable:
List<T> filterPresent(List<Optional<T>> inputs) {
return FluentIterable.from(inputs).filter(present()).transform(value()).toList();
}
static <T> Predicate<Optional<T>> present() {
return new Predicate<Optional<T>>() {
@Override
public boolean apply(Optional<T> optional) {
return optional.isPresent();
}
};
}
static <T> Function<Optional<T>, T> value() {
return new Function<Optional<T>, T>() {
@Override
public T apply(Optional<T> optional) {
return optional.get();
}
};
}
Unfortunately, there is no easier way in the pre-Java-8-life.
Upvotes: 0
Reputation: 62874
Why not do it in the old-fashioned Java way:
List<T> result = new ArrayList<T>();
for (Optional<T> optional : inputs) {
if (optional.isPresent()) {
result.add(optional.get());
}
}
return result;
Upvotes: 5