Combining multiple Optional
objects in Java in a functional style is a common need, especially when working with potentially nullable values without resorting to null checks. Here are examples of some approaches you can use based on the scenario:
1. Combining If All Optionals Are Present
If you want to combine values only when all Optional
s are non-empty, you can use flatMap()
and map()
to transform and combine their values.
Example:
package org.kodejava.util;
import java.util.Optional;
public class OptionalCombination {
public static void main(String[] args) {
Optional<String> optional1 = Optional.of("Hello");
Optional<String> optional2 = Optional.of("World");
Optional<String> combined = optional1.flatMap(val1 ->
optional2.map(val2 -> val1 + " " + val2)
);
// Output: Hello World
combined.ifPresent(System.out::println);
}
}
Here:
flatMap
is used on the firstOptional
.map
is applied on the secondOptional
inside theflatMap
block.- This ensures the operation occurs only if both
Optional
s are present.
2. Using Multiple Optionals Dynamically with Streams
If you have multiple Optional
objects, a dynamic approach using streams may be more suitable.
Example:
package org.kodejava.util;
import java.util.Optional;
import java.util.stream.Stream;
public class OptionalCombinationWithStreams {
public static void main(String[] args) {
Optional<String> optional1 = Optional.of("Hello");
Optional<String> optional2 = Optional.of("Functional");
Optional<String> optional3 = Optional.of("Java");
String result = Stream.of(optional1, optional2, optional3)
.flatMap(Optional::stream)
.reduce((s1, s2) -> s1 + " " + s2)
.orElse("No values");
// Output: Hello Functional Java
System.out.println(result);
}
}
Steps in this approach:
- Use
Stream.of()
to collect yourOptional
objects. - Extract their values using
flatMap(Optional::stream)
. - Combine the values with
reduce
.
3. Getting the First Non-Empty Optional
Sometimes, you’re only interested in the first non-empty Optional
. For this, you can use Optional.or()
, which was introduced in Java 9.
Example:
package org.kodejava.util;
import java.util.Optional;
public class FirstNonEmptyOptional {
public static void main(String[] args) {
Optional<String> optional1 = Optional.empty();
Optional<String> optional2 = Optional.of("Hello");
Optional<String> optional3 = Optional.empty();
Optional<String> firstPresent = optional1
.or(() -> optional2)
.or(() -> optional3);
// Output: Hello
firstPresent.ifPresent(System.out::println);
}
}
4. Handling Custom Logic with Optionals
You can define custom logic to process multiple Optionals and combine them using a utility function when needed.
Example:
package org.kodejava.util;
import java.util.Optional;
import java.util.stream.Stream;
import java.util.stream.Collectors;
public class OptionalCustomCombination {
public static void main(String[] args) {
Optional<Integer> optional1 = Optional.of(10);
Optional<Integer> optional2 = Optional.of(20);
Optional<Integer> optional3 = Optional.empty();
Optional<Integer> combined = combineOptionals(optional1, optional2, optional3);
combined.ifPresent(System.out::println); // Output: 30
}
@SafeVarargs
public static Optional<Integer> combineOptionals(Optional<Integer>... optionals) {
return Stream.of(optionals)
.flatMap(Optional::stream)
.collect(Collectors.reducing(Integer::sum));
}
}
In this example:
- The
combineOptionals
method dynamically handles any number ofOptional<Integer>
. - Non-empty values are summed using
Collectors.reducing()
.
Which Pattern Should You Use?
- Combine Only When All Optionals Are Present: Use
flatMap
andmap
chaining. - Combine Dynamically with Multiple Optionals: Use a
Stream
. - Use First Non-Empty Optional: Use
Optional.or()
. - Custom Processing Logic: Create a reusable utility method.
This way, you can handle Optional
objects cleanly and avoid verbose null checks.