Unlock Java 9‑16: New APIs, Immutable Collections, and Stream Enhancements

This article introduces Java 9‑16 features such as factory methods for immutable collections, Optional.ifPresentOrElse, new Stream operations like takeWhile/dropWhile and toList, plus enhanced Duration and LocalDate utilities, providing concise, modern code patterns for developers.

21CTO
21CTO
21CTO
Unlock Java 9‑16: New APIs, Immutable Collections, and Stream Enhancements

People often stick to long‑tested Java 7/8, but this article introduces useful new APIs from Java 9‑13.

Java 9 added factory methods for immutable collections:

List.of(E... elements)

Set.of(E... elements)

Map.ofEntries(Entry<? extends K, ? extends V>... entries)

Previously you had to create a mutable list and wrap it with Collections.unmodifiableList:

List<String> list = new ArrayList<>();
list.add("abc");
list.add("xyz");
Collections.unmodifiableList(list);

Now you can do it in one line:

List.of("abc","xyz");

Java 9 also introduced Optional.ifPresentOrElse to reduce boilerplate:

Optional<Email> mail = ...;
if (mail.isPresent()) {
    send(mail.get());
} else {
    reportError();
}

It can be rewritten more flexibly:

mail.ifPresentOrElse(
    m -> send(m),
    () -> reportError()
);

Further improvement with Optional.or:

Optional<String> optional = Optional.<String>ofNullable("first")
    .or(() -> Optional.of("second"));

Optional can produce a Stream directly:

Optional.of(obj).stream();

Compared to the older pattern:

Optional.of(obj).map(Stream::of).orElse(Stream.empty());

Stream interface gained new methods in later versions:

default Stream<T> takeWhile(Predicate<? super T> predicate)
default Stream<T> dropWhile(Predicate<? super T> predicate)

These allow predicate‑based limiting or skipping of elements.

Example using IntStream.iterate with a predicate:

IntStream.iterate(1, i -> i < 16, i -> i + 1)
    .forEach(System.out::println);

Equivalent to the older two‑step approach:

IntStream.iterate(1, i -> i + 1)
    .takeWhile(i -> i < 16)
    .forEach(System.out::println);

Java 16 introduced Stream.toList() which is more convenient and performant than collect(Collectors.toList()):

collection.stream()
    .toList();

Java.time got more utilities; Duration can now provide parts directly:

Duration dur = Duration.between(now().minusDays(10).minusSeconds(567), now());
System.out.println(dur.toDaysPart());   // 10
System.out.println(dur.toMinutesPart()); // 9

Duration also supports division and creation with ChronoUnit:

Duration dur = Duration.of(3, ChronoUnit.HOURS);
Duration ans = dur.dividedBy(Duration.of(20, ChronoUnit.MINUTES));
System.out.println(ans); // 9

LocalDate now has datesUntil to produce a stream of dates between two dates:

Stream<LocalDate> dates = LocalDate.of(2021,3,3)
    .datesUntil(LocalDate.of(2021,10,9));
JavaOptionalStream APIJava 9Immutable CollectionsJava 16Duration
21CTO
Written by

21CTO

21CTO (21CTO.com) offers developers community, training, and services, making it your go‑to learning and service platform.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.