Skip to content

Instantly share code, notes, and snippets.

@uraimo
Last active November 11, 2025 11:15
Show Gist options
  • Select an option

  • Save uraimo/8fb784f5d38b1bf5b12d1b6ed35c7778 to your computer and use it in GitHub Desktop.

Select an option

Save uraimo/8fb784f5d38b1bf5b12d1b6ed35c7778 to your computer and use it in GitHub Desktop.
Java optional and functional tips

Basics

Once you have a stream, flat to apply functions to elements and flatMap to unwrap elements returned internally as Optionals.

Load and convert if not null:

Optional.ofNullable(value).ifPresent(v -> BigDecimal.valueOf(Double.parseDouble(v)));

Filtering and get first match:

listOfElements.stream()
    .filter(v -> v.value > 0)
    .findFirst()
    .orElse(null);

Convert property to comma separated list:

listOfElements.stream()
    .map(e -> e.getName())
    .collect(Collectors.joining(","));
    
listOfElements.stream().reduce((acc,s) -> acc + "," + s).orElse("");

Get the length of a list of lists:

listOfLists.stream()
  .mapToInt(l -> l.size())
  .sum();

Has at least an element with a certain flag:

hasAdmins = listOfElements.stream().anyMatch(e -> e.getFlag().equalsIgnoreCase("ADMIN"));

Unique names:

listOfElements.stream().map(e -> e.getName())
    .distinct()
    .filter(s -> !s.isEmpty())
    .toList();

Extract the last from a sequence:

listOfElements.stream()
    .reduce((acc,s) -> s)
    .orElse("");

Group elements in a list by some common property:

Map<Side,List<Leg>> legsBySide = legs.stream()
    .collect(groupingBy(Leg::getSide,LinkedHashMap::new, toList()));

Filter out null object with null-check:

elements.stream().filter(Objects::nonNull);

Make a single stream of elements from a stream of sublists:

streamOfLists.flatMap(Collection::stream).collect(Collector.toList());

Advanced

Turn a List<Optional<String>> to a List<String> removing null elements without null checks:

List<Optional<String>> someStrings = ...;

List<String> allPresentStrings = someStrings.stream()
  .flatMap(Optional::stream)
  .collect(Collectors.toList());

Turn a List<List<String>> to a List<String>:

 List<List<String>> someStrings = ...;

List<String> allPresentStrings = someStrings.stream()
  .flatMap(List::stream)
  .collect(Collectors.toList());

While mapping a stream return multiple elements in one of the steps:

List<String> strings = items.stream()
  .flatMap(item -> Streams.of("string1","string2"))
  .toList();

Concat mutliple streams:

Streams.concat(stream1,Streams.concat(stream2,stream3))

Group by key and extract the max using another key:

Map<String, Optional<Car>> groupByMaxPrice = carsDetails.stream().collect(
    Collectors.groupingBy(
      Car::getMake, 
      Collectors.maxBy(Comparator.comparing(Car::getPrice)
));

More elegant handling of exceptions inside maps, use a function that catches returning an empty optional after an exception, and then flatmap back to the original type the resulting stream of optionals.

public static <V,T> Function<v, Optional<T>> catchAsOptional(Logger logger, Function<V,T> closure){
    return param -> {
        try{
            return Optional.ofNullable(closure.apply(param));
        }catch(Exception e){
            logger.error(e.getMessage(),e);
            return Optional.empty();
        }
    };
}

...stream()
.map(catchAsOptional(logger,(TypeV v) -> functionThatThrowsReturningT(v, param2)) //Box the function in an optional, empty after an exception
.flatMap(Optional::stream); //Filter out empty optionals and unbox them
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment