Explore Java 17’s New Time Formatting, Stream toList, mapMulti, and HexFormat

This article walks through Java 17’s lesser‑known enhancements—including the “B” pattern for time‑of‑day formatting, the concise Stream.toList() method, the versatile mapMulti() operation with practical examples, and the new HexFormat utility for hex conversions—while highlighting related bug fixes and usage tips.

Java Architecture Diary
Java Architecture Diary
Java Architecture Diary
Explore Java 17’s New Time Formatting, Stream toList, mapMulti, and HexFormat

1. Introduction

Besides the well‑known JEPs, Java 17 includes many other features. First, verify your Java version:

$ java --version
openjdk 17 2021-09-14
OpenJDK Runtime Environment (build 17+35-2724)
OpenJDK 64-Bit Server VM (build 17+35-2724, mixed mode, sharing)

Now let’s explore these treasures.

2. New Feature (JDK 16): “B” pattern for java.time formatting

The “B” pattern represents a time‑of‑day period such as “morning”, “afternoon”, or “evening”. It is added to DateTimeFormatter and DateTimeFormatterBuilder with built‑in internationalization support.

String format = DateTimeFormatter.ofPattern("B").format(LocalTime.now());
System.out.println(format); // 上午

3. New Feature (JDK 16): Stream.toList() method

Since Java 8 introduced the Stream API, converting a list often required verbose code. The new toList() method shortens the pipeline:

numbers.stream().map(Integer::valueOf).toList();

Two important points: Stream.toList() returns an unmodifiable list and does not accept null values, throwing a NullPointerException.

It is not a shorthand for collect(toUnmodifiableList()); it bypasses the Collector contract and uses less memory when the stream size is known.

4. New Feature (JDK 16): Stream.mapMulti() method

The mapMulti() default method is added to the Stream interface, with specialized versions for int, long, and double. It replaces each element with zero or more elements by invoking the provided mapper multiple times.

4.1 Zero‑to‑one mapping

Using mapMulti() you can filter and transform elements in a single pipeline:

Stream.of("Java","Valhalla","Panama","Loom","Amber")
    .mapMulti((str, mapper) -> {
        if (str.length() >= 5) mapper.accept(str.length());
    })
    .forEach(i -> System.out.print(i + " ")); // 8 6 5

4.2 One‑to‑one mapping

When each element maps to exactly one result, mapMulti() behaves like map():

Stream.of("Java","Valhalla","Panama","Loom","Amber")
    .mapMulti((str, mapper) -> mapper.accept(str.length()))
    .forEach(i -> System.out.print(i + " ")); // 4 8 6 4 5

4.3 One‑to‑many mapping

The mapper can be called multiple times per element, enabling transformations such as expanding a string into repeated characters:

Stream.of("Java","Valhalla","Panama","Loom","Amber","")
    .mapMulti((str, mapper) -> {
        for (int i = 0; i < str.length(); i++) {
            mapper.accept(str.length());
        }
        mapper.accept(" ");
    })
    .forEach(System.out::print); // 4444 88888888 666666 4444 55555

When to prefer mapMulti() over flatMap() ? mapMulti() allows the mapper to emit zero or many elements without creating intermediate stream objects, leading to better performance in scenarios with few output elements per input or when an imperative approach is simpler.

5. Bug Fix (JDK 16): Path.of / Paths.get null‑first‑argument check

Both methods now consistently throw NullPointerException when the first argument is null:

Path path = Path.of(null, "path/to/file");
// Exception java.lang.NullPointerException

6. New Feature (JDK 17): java.util.HexFormat

The immutable, thread‑safe HexFormat class converts between bytes, chars, and hex strings, supporting custom prefixes, suffixes, and delimiters. Equality should be checked with equals().

// Default format
HexFormat hex = HexFormat.of();
byte b = 127;
String byteStr = hex.toHexDigits(b); // "7f"
byte digits = (byte) HexFormat.fromHexDigits(byteStr); // 127

// Custom format
HexFormat format = HexFormat.of()
    .withPrefix("mica")
    .withDelimiter(" ")
    .withSuffix("微服务")
    .withUpperCase();

String hexStr = format.formatHex("123".getBytes());
// mica31微服务 mica32微服务 mica33微服务
byte[] hexBytes = format.parseHex(hexStr);
System.out.println(new String(hexBytes)); // "123"

7. Conclusion

The series has already published several Java 17 articles, with more in preparation.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

JavaBackend DevelopmentStream APIjava-17HexFormatmapMulti
Java Architecture Diary
Written by

Java Architecture Diary

Committed to sharing original, high‑quality technical articles; no fluff or promotional content.

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.