5
Java language feature series

sequence

This article mainly talks about the new features of Java 19

version number

 java -version
openjdk version "19" 2022-09-20
OpenJDK Runtime Environment (build 19+36-2238)
OpenJDK 64-Bit Server VM (build 19+36-2238, mixed mode, sharing)
It can be seen from the version information that it is build 19+36

Feature list

JEP 405: Record Patterns (Preview)

The pattern matching of instanceof is used as a preview in JDK14, in JDK15 as the second round preview, and in JDK16 JEP 394: Pattern Matching for instanceof becomes positive
switch pattern matching was introduced in JDK17's JEP 406: Pattern Matching for switch (Preview) as the preview version, and in JDK18's JEP 420: Pattern Matching for switch (Second Preview) as the second round of preview

For the record type, the introduction of instance of can be written like this

 record Point(int x, int y) {}

static void printSum(Object o) {
    if (o instanceof Point p) {
        int x = p.x();
        int y = p.y();
        System.out.println(x+y);
    }
}

Now you can write

 record Point(int x, int y) {}

void printSum(Object o) {
    if (o instanceof Point(int x, int y)) {
        System.out.println(x+y);
    }
}

More complex example:

 record Point(int x, int y) {}
enum Color { RED, GREEN, BLUE }
record ColoredPoint(Point p, Color c) {}
record Rectangle(ColoredPoint upperLeft, ColoredPoint lowerRight) {}

Rectangle r = new Rectangle(new ColoredPoint(new Point(x1, y1), c1), 
                            new ColoredPoint(new Point(x2, y2), c2));

static void printXCoordOfUpperLeftPointWithPatterns(Rectangle r) {
    if (r instanceof Rectangle(ColoredPoint(Point(var x, var y), var c),
                               var lr)) {
        System.out.println("Upper-left corner: " + x);
    }
}

If it is a generic record:

 record Box<T>(T t) {}

static void test1(Box<Object> bo) {
    if (bo instanceof Box<Object>(String s)) {
        System.out.println("String " + s);
    }
}
static void test2(Box<Object> bo) {
    if (bo instanceof Box<String>(var s)) {
        System.out.println("String " + s);
    }
}

JEP 422: Linux/RISC-V Port

RISC-V is an open source instruction set architecture (ISA) based on the principle of reduced instruction set (RISC), and this JEP transplants JDK to RISC-V

JEP 424: Foreign Function & Memory API (Preview)

The Foreign Function & Memory (FFM) API includes two incubation APIs
JEP 370: Foreign-Memory Access API (Incubator) of JDK14 introduces the Foreign-Memory Access API as an incubator
JDK15's JEP 383: Foreign-Memory Access API (Second Incubator) Foreign-Memory Access API as a second-round incubator
JDK16's JEP 393: Foreign-Memory Access API (Third Incubator) As the third round, it introduces the Foreign Linker API (JEP 389 )
The FFM API was introduced as an incubator in JDK 17's JEP 412: Foreign Function & Memory API (Incubator)
FFM API in JDK 18's JEP 419: Foreign Function & Memory API (Second Incubator) as a second round incubator
This JEP of JDK19 uses the FFM API as the preview API

Example of use

 // 1. Find foreign function on the C library path
Linker linker = Linker.nativeLinker();
SymbolLookup stdlib = linker.defaultLookup();
MethodHandle radixSort = linker.downcallHandle(
                             stdlib.lookup("radixsort"), ...);
// 2. Allocate on-heap memory to store four strings
String[] javaStrings   = { "mouse", "cat", "dog", "car" };
// 3. Allocate off-heap memory to store four pointers
SegmentAllocator allocator = SegmentAllocator.implicitAllocator();
MemorySegment offHeap  = allocator.allocateArray(ValueLayout.ADDRESS, javaStrings.length);
// 4. Copy the strings from on-heap to off-heap
for (int i = 0; i < javaStrings.length; i++) {
    // Allocate a string off-heap, then store a pointer to it
    MemorySegment cString = allocator.allocateUtf8String(javaStrings[i]);
    offHeap.setAtIndex(ValueLayout.ADDRESS, i, cString);
}
// 5. Sort the off-heap data by calling the foreign function
radixSort.invoke(offHeap, javaStrings.length, MemoryAddress.NULL, '\0');
// 6. Copy the (reordered) strings from off-heap to on-heap
for (int i = 0; i < javaStrings.length; i++) {
    MemoryAddress cStringPtr = offHeap.getAtIndex(ValueLayout.ADDRESS, i);
    javaStrings[i] = cStringPtr.getUtf8String(0);
}
assert Arrays.equals(javaStrings, new String[] {"car", "cat", "dog", "mouse"});  // true

JEP 425: Virtual Threads (Preview)

Virtual threads should be the most important feature of JDK19. The first integration is the API of preview
Virtual threads are user-mode threads provided by JDK, similar to goroutines in golang and processes in erlang
The virtual thread adopts the M:N scheduling mode, that is, M number of virtual threads run on N Threads, using ForkJoinPool to schedule in FIFO mode, N is Runtime.availableProcessors() by default, you can pass jdk.virtualThreadScheduler.parallelism to modify

Example of use

 try (var executor = Executors.newVirtualThreadPerTaskExecutor()) {
    IntStream.range(0, 10_000).forEach(i -> {
        executor.submit(() -> {
            Thread.sleep(Duration.ofSeconds(1));
            return i;
        });
    });
}  // executor.close() is called implicitly, and waits
As above, a few OS threads are used to run 10,000 virtual threads. Virtual threads can significantly improve the throughput of the system in more than a thousand non-CPU-intensive concurrent task scenarios.
 void handle(Request request, Response response) {
    var url1 = ...
    var url2 = ...
 
    try (var executor = Executors.newVirtualThreadPerTaskExecutor()) {
        var future1 = executor.submit(() -> fetchURL(url1));
        var future2 = executor.submit(() -> fetchURL(url2));
        response.send(future1.get() + future2.get());
    } catch (ExecutionException | InterruptedException e) {
        response.fail(e);
    }
}
 
String fetchURL(URL url) throws IOException {
    try (var in = url.openStream()) {
        return new String(in.readAllBytes(), StandardCharsets.UTF_8);
    }
}
Although this scenario is block code, because virtual threads are introduced, the system can scale well; when virtual threads are blocked in IO or other operations ( BlockingQueue.take() ), virtual threads will be removed from Thread unmount, when the operation is completed, remount it to continue execution. However, some operations will not unmount the virtual thread, and will block together with the thread and the underlying OS thread (such as entering a synchronized code block/method, such as executing a native method or foreign function).
The overhead of virtual threads is not large, so there is no need to use pooling technology to use jcmd <pid> Thread.dump_to_file -format=json <file> You can dump virtual threads in json format, examples are as follows
dump 虚拟线程
Thread.Builder, Thread.ofVirtual(), Thread.ofPlatform() can be used to create virtual threads or platform threads, such as
 Thread thread = Thread.ofVirtual().name("duke").unstarted(runnable);
Thread.startVirtualThread(Runnable) Equivalent to creating and starting a virtual thread
Thread.threadId() as a final method returns the thread ID, while non-final Thread.getId() is deprecated
Thread.getAllStackTraces() now returns platform threads instead of all threads

JEP 426: Vector API (Fourth Incubator)

JDK16 introduced JEP 338: Vector API (Incubator) provides jdk.incubator.vector for vector computation
JDK17 improves and serves as the second round of incubator JEP 414: Vector API (Second Incubator)
JDK18's JEP 417: Vector API (Third Incubator) is improved and used as the third-round incubator, while JDK19 is used as the fourth-round incubator

JEP 427: Pattern Matching for switch (Third Preview)

The pattern matching of instanceof is used as a preview in JDK14, as a second-round preview in JDK15, and positive in JDK16
JDK17 introduces JEP 406: Pattern Matching for switch (Preview)
JEP 420: Pattern Matching for switch (Second Preview) of JDK18 is used as the second round preview, and JDK19 is used as the third round preview

JEP 428: Structured Concurrency (Incubator)

Structured concurrency is also an important feature of JDK19. ExecutorService introduced by JDK5 can be used to process tasks in parallel, such as
 Response handle() throws ExecutionException, InterruptedException {
    Future<String>  user  = esvc.submit(() -> findUser());
    Future<Integer> order = esvc.submit(() -> fetchOrder());
    String theUser  = user.get();   // Join findUser
    int    theOrder = order.get();  // Join fetchOrder
    return new Response(theUser, theOrder);
}
But when findUser throws an exception, fetchOrder will continue to run in its own thread, or findUser needs to run for a long time, and when fetchOrder is abnormal, the entire handle method still needs to waste time waiting for findUser to finish executing, it blocks in user.get ( ). In order to better handle the cancellation of other subtasks in abnormal scenarios, structured concurrency is introduced to solve this problem, mainly the StructuredTaskScope class, which can fork subtasks and then join or cancel together.
 Response handle() throws ExecutionException, InterruptedException {
    try (var scope = new StructuredTaskScope.ShutdownOnFailure()) {
        Future<String>  user  = scope.fork(() -> findUser());
        Future<Integer> order = scope.fork(() -> fetchOrder());

        scope.join();           // Join both forks
        scope.throwIfFailed();  // ... and propagate errors

        // Here, both forks have succeeded, so compose their results
        return new Response(user.resultNow(), order.resultNow());
    }
}
If one of the subtasks fails, the other running task is canceled. After scope.join(), you can use resultNow() or exceptionNow() to get the result

Detailed Interpretation

Listed above are major features, in addition to some API updates and discards, mainly see JDK 19 Release Notes , here are a few examples.

Add item

  • System Properties for System.out and System.err ( JDK-8283620 )

    Added stdout.encoding these two system properties stderr.encoding
  • Support Unicode 14.0 ( JDK-8268081 )

    Added support for unicode version 14.0
  • Additional Date-Time Formats ( JDK-8176706 )

    In the past, java.time.format.DateTimeFormatter/DateTimeFormatterBuilder only supported four kinds of FormatStyle.FULL/LONG/MEDIUM/SHORT. Now it can be customized, such as DateTimeFormatter.ofLocalizedPattern("yMMM")
  • Automatic Generation of the CDS Archive ( JDK-8261455 )

    Added -XX:+AutoCreateSharedArchive parameter can automatically create CDS archive, such as java -XX:+AutoCreateSharedArchive -XX:SharedArchiveFile=app.jsa -cp app.jar App

remove item

  • Remove Finalizer Implementation in SSLSocketImpl ( JDK-8212136 )

    Remove finalizer implementation of SSLSocket
  • Removal of Diagnostic Flag GCParallelVerificationEnabled ( JDK-8286304 )

    Remove GCParallelVerificationEnabled parameter

obsolete

For a complete list see Java SE 19 deprecated-list

  • java.lang.ThreadGroup Is degraded ( JDK-8284161 )

    ThreadGroup can no longer be shown destroyed, it now no longer holds a strong reference to its subgroup
  • Deprecation of Locale Class Constructors ( JDK-8282819 )

    The Locale constructor is deprecated and can be replaced by the Locale.of() factory method

Known Issues

  • ForkJoinPool and ThreadPoolExecutor do not use Thread::start to Start Worker Threads ( JDK-8284161 )

    ForkJoinPool and ThreadPoolExecutor no longer use `Thread::start to start threads in this version, so those worker threads that override start without parameters may be affected, but ForkJoinWorkerThread.onStart() is not affected
  • InflaterInputStream.read Throws EOFException ( JDK-8292327 )

    InflaterInputStream may throw EOFException in this version
  • G1 Remembered set memory footprint regression after JDK-8286115 ( JDK-8292654 )

    JDK-8286115, which changes the ergonomic size of G1's RSet, will increase local memory usage, which can be alleviated by increasing the value of G1RemSetArrayOfCardsEntries, such as
     -XX:+UnlockExperimentalVMOptions -XX:G1RemSetArrayOfCardsEntries=128

something else

  • JNI GetVersion Returns JNI_VERSION_19 ( JDK-8286176 )

    The jni method GetVersion returns JNI_VERSION_19
  • Double.toString(double) and Float.toString(float) may Return Slightly Different Results ( JDK-4511638 )

    Double.toString(2e23), now returns "2.0E23", whereas previous versions returned "1.9999999999999998E23"
  • Make HttpURLConnection Default Keep Alive Timeout Configurable ( JDK-8278067 )

    Added http.keepAlive.time.server and http.keepAlive.time.proxy system properties that can be used to modify the default Keep Alive Timeout
  • JVM TI Changes to Support Virtual Threads ( JDK-8284161 )

    The JVM Tool Interface (JVM TI) has been updated to support virtual threads
  • -Xss may be Rounded up to a Multiple of the System Page Size ( JDK-8236569 )

    The actual java thread stack size may differ from the value specified by the -Xss command line option; it may be rounded to a multiple of the page size required by the system.

summary

Java18 mainly has the following features

doc


codecraft
11.9k 声望2k 粉丝

当一个代码的工匠回首往事时,不因虚度年华而悔恨,也不因碌碌无为而羞愧,这样,当他老的时候,可以很自豪告诉世人,我曾经将代码注入生命去打造互联网的浪潮之巅,那是个很疯狂的时代,我在一波波的浪潮上留下...


引用和评论

0 条评论