Reputation: 17032
I am looking to avoid multiple if-else
conditions. Is there a more concise way of writing the below code?
private Set<String> getValues(Optional<String> one, Optional<String> two) {
if (one.isPresent() && two.isPresent()) {
return ImmutableSet.of(one.get(), two.get());
} else if (one.isPresent()) {
return ImmutableSet.of(one.get());
} else {
return two.isPresent() ? ImmutableSet.of(two.get()) : ImmutableSet.of();
}
}
Upvotes: 2
Views: 261
Reputation: 11620
The simplest solution would be to use Optional.stream(), jdk9+:
private Set<String> getValuesJdk9(Optional<String> one, Optional<String> two) {
return Stream.concat(one.stream(), two.stream())
.collect(Collectors.toUnmodifiableSet());
}
You can read more here
If You are using JDK8 still:
private Set<String> getValuesJdk8(Optional<String> one, Optional<String> two) {
return Stream.of(one, two)
.filter(Optional::isPresent)
.map(Optional::get)
.collect(Collectors.toUnmodifiableSet());
}
And one extreme version, when You can pass any number of arguments
private Set<String> getAllValues(Optional<String>... options) {
return Arrays.stream(options).flatMap(Optional::stream)
.collect(Collectors.toUnmodifiableSet());
}
Upvotes: 10
Reputation: 29038
According to the documentation Collector Collectors.toSet()
(used in another answer) gives no guarantees on the mutability of the returned Set
. Currently, it provides a mutable general purpose implementation - HashSet
.
If you need an Immutable Set
here are the options:
There are several ways to generate an Unmodifiable Set offered by JDK.
And you can make use of the Guava's features that allow to produce ImmutableSet
including Collector
ImmutableSet.toImmutableSet()
.
Firstly, it's a discouraged practice to pass around Optional
s.
Here's quote from the answer by Brian Goetz, Java Language Architect, regurding the disign goals of Optional
:
Our intention was to provide a limited mechanism for library method return types where there needed to be a clear way to represent "no result", and using null for such was overwhelmingly likely to cause errors.
For example, you probably should never use it for something that returns an array of results, or a list of results; instead return an empty array or list. You should almost never use it as a field of something or a method parameter.
Also see the answer by Stuart Marks, Java and OpenJDK developer Uses for Optional.
A cleaner alternative to using Optional
as method parameter passing around the Optional
you can provide a Supplier
of Optional
and evaluate it inside your method.
Assuming you have methods foo()
and bar()
returning an Optional
, then if you change the method signature to:
getValues(Supplier<Optional<T>> first, Supplier<Optional<T>> second)
Then you can invoke the method like that: getValues(x::foo, y::bar)
And instead of operating with two optionals the problem can be generified to:
"Collect N values from non-empty Optionals into an ImmutableSet"
ImmutableSet.toImmutableSet()
Since Guava release version 21.0
(which requires JDK 8 as a minimum version) you can use Collector
returned by ImmutableSet.toImmutableSet()
.
@SafeVarargs
private static <T> Set<T> getValues(Supplier<Optional<T>>... suppliers) {
return Arrays.stream(suppliers)
.map(Supplier::get)
.filter(Optional::isPresent)
.map(Optional::get)
.collect(ImmutableSet.toImmutableSet());
}
And just for the purpose of completeness, here's a solution with no dependencies required.
Since Java 10 Collector toUnmodifiableSet()
is available in the JDK.
@SafeVarargs
private static <T> Set<T> getValues(Supplier<Optional<T>>... suppliers) {
return Arrays.stream(suppliers)
.map(Supplier::get)
.filter(Optional::isPresent)
.map(Optional::get)
.collect(Collectors.toUnmodifiableSet());
}
Upvotes: 1