java 21


Abstract

  • project Loom: virtual threads + structured concurrency (preview)
  • GC ZGCC: pause in microseconds vs milliseconds with drawbacks less throughput and more memory consumption
  • project Panama: better support with native code
  • project Amber: Java language quality of life

String templates (preview)

Abstract

  • simplify string concatenation
  • enable domain-specific processing
  • incentivize the “right way”

Template processor STR

String form = STR."""
    Desc     Unit   Qty   Amount
    \{desc} $\{price} \{qty} $\{price * qty}
 
    Subtotal  $\{price * qty}
    Tax       $\{price * qty * tax}
    Total     $\{price * qty * (1.0 + tax)}
    """;

outputs:

Desc     Unit   Qty   Amount
hammer   $7.88  3     $23.64

Subtotal  $23.64
Tax       $3.546
Total     $27.186

Template processor FMT

String form = FMT."""
    Desc        Unit      Qty   Amount
    %-10s\{desc} $%5.2f\{price} %5d\{qty} $%5.2f\{price * qty}
 
    Subtotal  $%5.2f\{price * qty}
    Tax       $%5.2f\{price * qty * tax}
    Total     $%5.2f\{price * qty * (1.0 + tax)}
    """;

outputs:

Desc        Unit      Qty   Amount
hammer      $ 7.88      3   $23.64

Subtotal  $23.64
Tax       $ 3.55
Total     $27.19

Custom templating

public interface Processor<RESULT, EX> {
    RESULT process(StringTemplate s) throws EX;
}
  • STR is a singleton instanec of a Processor implementation.
  • RESULT can be of any type!

Examples:

// prevents SQL injections
Statement query = SQL."""
    SELECT * FROM Person p
    WHERE p.\{property} = '\{value}'
    """;
// validates & escapes JSON
JSONObject doc = JSON."""
    {
        "name": "\{name}",
        "year": "\{bday.getYear()}"
    }
    """;

Sequence Collections

Collections with order and indexed access:

  • List

Collections with order without indexed access:

  • SortedSet (sort order)
  • Deque (insertion order)
  • LinkedHashSet (insertion order)
  • and more

New interfaces capture the concept of order:

  • SequencedCollection
  • SequencedSet
  • SequencedMap

with new API:

  • void addFirst(E);
  • void addLast(E);
  • E getFirst();
  • E getLast();
  • E removeFirst();
  • E removeLast();
  • SequencedCollection<E> reversed();

Misc improvements

Right-sizing hashing data structures

  • HashMap.newHashMap(int numMappings)
  • HashSet.newHashSet(int numElements)
  • LinkedHashMap.newLinkedHashMap(int numMappings)
  • LinkedHashSet.newLinkedHashSet(int numElements)

More AutoCloseable

  • HttpClient
  • ExecutorService
  • ForkJoinPool

Strings and Builders

  • "String".indexOf(String str, int beginIndex, int endIndex)

DateTimeFormatter

  • DateTimeFormatter.ofPattern("y-MM-dd") 2023-10-02
  • DateTimeFormatter.ofLocalizedDate(FormatStyle.SHORT) 10/2/23 using locale en_US
  • DateTimeFormatter.ofLocalizedPattern("yMM") 02/10/2023 using locale en_US

Better Future

  • T resultNow()
  • Throwable exceptionNow
  • State state()

Generational ZGC

  • optimized for ultra-low pause times
  • can have higher memory footprint or higher CPU usage

Virtual Threads

Solve conflit between simplicity and throughput.

There are other conflicts:

  • design vs performance ( Valhalla)
  • explicitness vs succinctness ( Amber)
  • flexibility vs safety ( Panama)
  • optimization vs specification ( Leyden)

What is a Virtual Thread

A virtual thread:

  • is a regular Thread
  • low memory footprint ([k]bytes)
  • small switching cost
  • scheduled by the Java runtime
  • requires no OS thread when waiting

Virtual memory:

  • maps large virtual address space to limited physical memory
  • gives illusion of plentiful memory

Virtual threads:

  • map large number of virtual threads to a small number of OS threads
  • give the illusion of plentiful threads

virtual threads|800

Sample

try (var executor = Executors
        .newVirtualThreadPerTaskExecutor()) {
    IntStream
        .range(0, 1_000_000)
        .forEach(number -> {
            executor.submit(() -> {
                Thread.sleep(Duration.ofSeconds(1));
                return number;
            });
        });
}

Effects

  • remove “number of threads” as bottleneck
  • match app’s unit of concurrency to Java’s simplicity && throughput
  • viturla threads increase throughput

Performance

Virtual threads aren’t “faster threads”:

  • same number of CPU cycles
  • each tasks takes the same time (same latency)

Parallelism VS concurrency

ParallelismConcurrency
Task originsolutionproblem
Controldeveloperenvironment
Resource usecoordinatedcompetitive
Metriclatencythroughput
AbstractionCPU corestasks
# of threads# of cores# of tasks

Example of using Virtual Threads on web frameworks

Spring Boot:

Bean
public TomcatProtocolHandlerCustomizer<?>
        createExecutorForSyncCalls() {
    return handler -> handler.setExecutor(
            Executors.newVirtualThreadPerTaskExecutor());
}
 
@Bean
public AsyncTaskExecutor
        createExecutorForAsyncCalls() {
    return new TaskExecutorAdapter(
            Executors.newVirtualThreadPerTaskExecutor());
}

Data-Oriented Programming

  • model the data, the whole data, and nothing but the data
  • data is immutable
  • validate at the boundary
  • make illegal states unrepresentable

Use sealed types to model the alternatives:

  • communicates intention to developers
  • allow compiler to check exhaustiveness

Pattern matching on sealed types is perfect to apply polymorphic operations to data! And records eschew encapsulation, so everything is accessible.

To keep operations maintainable:

  • switch over sealed types
  • enumerate all possible types (even if you need to ignore some)
  • avoid default branch

like the visitor pattern, but less painful



Abstract

Some improvements were implemented in some native Java classes, such as RandomAccess*, so it will improve lots of things, as they are also used by a lot of libraries and frameworks.