Get Even More Visitors To Your Blog, Upgrade To A Business Listing >>

A categorized list of all Java and JVM features since JDK 8 to 21

(Read this article on the blog)

Last updated on 2023/09/22 to include changes up to JDK 21.

This article is also available in Chinese by Alex Tan.

Since the release of version 8, up to version 21, Java is shaped by 232 JDK Enhancement Proposals (JEPs) and many more smaller updates, each of which brings some improvement to the platform. This page is a categorized and curated list of the most important improvements.

Contents of this page:

  • New Language Features
  • New APIs
  • Performance Improvements
  • Security Improvements
  • Launching
  • Packaging
  • Javadoc
  • Bytecode
  • New supported platforms
  • New Version Scheme
  • Deprecation and removal

The full list of JEPs can be found on the OpenJDK website under the jdk and jdk9 projects.

All features are generally available and enabled by default, except if they are labelled with one of the following:

  • Preview 🔍 features are fully specified and implemented, but not yet considered to be final. They are considered to be almost complete, waiting for an additional round of real-world feedback. They have to be explicitly enabled.
  • Experimental 💥 features are less stable, and more likely to change. They also have to be explicitly enabled.
  • Incubator 🥚 modules are non-final tools and API’s, and are distributed in separate modules.

New Language Features

Since Java 8 lots of improvements were made to the language. This section is a quick recap on what happened in the last years. For a more in-depth guide, see New language features since Java 8.

  • Pattern Matching for switch supporting type patterns and guarded patterns
    JDK 21 (Preview 🔍 in JDK 20 JDK 19 JDK 18 JDK 17)
    String formatted = switch (o) {
        case Integer i when i > 10 -> String.format("a large Integer %d", i);
        case Integer i             -> String.format("a small Integer %d", i);
        case Long l                -> String.format("a Long %d", l);
        default                    -> o.toString();

    → Related: Inside Java - Episode 17 “Pattern Matching for switch” with Gavin Bierman
    → Inside Java Podcast Episode 26: “Java 19 is Here!” with Brian Goetz and Ron Pressler
    → Inside Java Podcast Episode 28: “Java Language - State of the Union” with Gavin Bierman

  • Record Patterns for switch and instanceof to deconstruct complex nested structures
    JDK 21 (Preview in JDK 20 JDK 19)
    if (r instanceof ColoredPoint(Point2D(int x, int y), Color c)) {
      // work with x, y, and c
  • Unnamed Variables (Preview 🔍)
    JDK 21
    var _ = mySet.add(x); // ignore the return value
    try {
      // ...
    } catch (Exception _) { // ignore the exception object
      // ...
      .map((_) -> /* ... */) // ignore the parameter
  • Unnamed Patterns (Preview 🔍)
    JDK 21
    if (r instanceof Point(int x, _)) {
      // work with x, ignore second parameter
  • String Templates - extensible and safe String interpolation (Preview 🔍)
    JDK 21
    var name = "Duke";
    var info = STR."My name is \{name}";
  • Unnamed Classes and Instance Main Methods (Preview 🔍)
    JDK 21
    // This is a complete and runnable program!
    void main() {
      System.out.println("Hello, World!");
  • Sealed Classes can restrict which other classes may extend them
    JDK 17 (Preview 🔍 in JDK 16 JDK 15)
    public abstract sealed class Shape
        permits Circle, Rectangle {...}
    public final class Circle extends Shape {...} // OK
    public final class Rectangle extends Shape {...} // OK
    public final class Triangle extends Shape {...} // Compile error
    // No need for default case if all permitted types are covered
    double area = switch (shape) {
        case Circle c    -> Math.pow(c.radius(), 2) * Math.PI
        case Rectangle r -> r.a() * r.b()
  • Record Classes, terse syntax to define immutable DTOs
    JDK 16 (Preview 🔍 in JDK 15 JDK 14)
    record Point(int x, int y) { }
    var point = new Point(1, 2);
    point.x(); // returns 1
    point.y(); // returns 2

    → Related: Inside Java - Episode 14 “Records Serialization” with Julia Boes and Chris Hegarty

  • Pattern Matching for instanceof to eliminate the need for explicit casts after a type check
    JDK 16 (Preview 🔍 in JDK 15 JDK 14)
    if (obj instanceof String s && s.length() > 5) {
        System.out.println("obj is a String with more than 5 characters: " + s.toUpperCase());
  • Text Blocks
    JDK 15 (Preview 🔍 in JDK 14 JDK 13)
    String html = """

    Hello, world

  • Helpful NullPointerExceptions describing precisely which variable was null
    JDK 15 (Enabled with -XX:+ShowCodeDetailsInExceptionMessages in JDK 14)
    a.b.c.i = 99;
    Exception in thread "main" java.lang.NullPointerException:
          Cannot read field "c" because "a.b" is null
  • Switch Expressions
    JDK 14 (Preview 🔍 in JDK 12 JDK 13)
    int numLetters = switch (day) {
        case MONDAY, FRIDAY, SUNDAY -> 6;
        case TUESDAY                -> 7;
        default      -> {
          String s = day.toString();
          int result = s.length();
          yield result;
  • Introduction of var to make local variable declarations less ceremonious
    JDK 11 (Without lambda support in JDK 10)
    var greeting = "Hello World!";
  • Opt-in and backwards-compatible Module System to avoid ClassDefNotFoundErrors at runtime and create internal APIs
    JDK 9 (Project Jigsaw)
    module hu.advancedweb.helloworld {
        requires hu.advancedweb.somedependency;
        exports hu.advancedweb.hello
  • Private methods in interfaces
    JDK 9 (Milling Project Coin)

  • Diamond operator for anonymous inner classes
    JDK 9 (Milling Project Coin)

  • Try-with-resources allows effectively final variables
    JDK 9 (Milling Project Coin)

  • @SafeVargs on private instance methods
    JDK 9 (Milling Project Coin)

  • No deprecation warnings on import statements
    JDK 9

New APIs

Let’s continue with the Java Standard Library, focusing on the new features that we can use in day-to-day coding.

If you are curious about all the API level differences between Java 8 later versions, check the AdoptOpenJDK/jdk-api-diff on GitHub or the The Java Version Almanac.


  • Sequenced Collections add interfaces to represent encounter order in collections, allowing, for example, LinkedHashSet to serve as a substitute for a List and adding convenience methods like getFirst and reverse
    JDK 21
    void doSomething(SequencedCollection seq) {
      // ...
    var set = new LinkedHashSetString>();
    var list = new ArrayListString>();

    → Inside Java Podcast Episode 31 “Sequenced Collections” with Stuart Marks

  • Math.clamp to fit the argument between min/max boundaries
    JDK 21

  • StringBuffer.repeat and StringBuilder.repeat
    JDK 21

  • splitWithDelimiters split variant for String and Pattern that also returns the matching delimiters
    JDK 21

  • BigInteger.parallelMultiply, an efficient and parallel implementation to multiply really huge numbers
    JDK 19

  • BigDecimal.TWO because ONE is not enough
    (the real reason is to make BigDecimal consistent with BigInteger)
    JDK 19

  • Math.divideExact for long and int to perform a division and throw an exception if the result overflows
    JDK 18

  • Java APIs that depend on the default charset will use UTF-8 by default
    (e.g. InputStreamReader, FileReader, OutputStreamWriter, FileWriter, PrintStream, Formatter, Scanner)
    If you need the old behavior check the file.encoding and the native.encoding system properties.
    JDK 18
    → Related: Inside Java - Episode 23 “Java 18 is Here” with Naoto Sato

  • Service-provider interface for host name and address resolution, enabling mock resolvers in test scenarios and allowing frameworks to have finer control over resolution results
    JDK 18

  • Process::inputReader, Process::outputWritter, Process::errorReader to access the standard input, output and error streams of the process
    JDK 17

  • java.time.InstantSource, an interface that provides the current instant, an abstraction from java.time.Clock that only focuses on the current instant and does not refer to the time zone
    JDK 17

  • HexFormat to encode and decode of hexadecimal strings
    JDK 17
    //  ==> "0000007b"
    // ==> 123
  • Vector API to express computations that compile to optimal hardware instructions (Incubator 🥚)
    JDK 18 JDK 17 JDK 16

  • Foreign linker API for statically-typed, pure-Java access to native code (Incubator 🥚)
    JDK 18 JDK 17 JDK 16

  • Foreign memory access API to access memory outside of the Java heap (Incubator 🥚)
    JDK 18 JDK 17 JDK 16

  • Align random generators (Random, ThreadLocalRandom, and SplittableRandom) by providing common interfaces making it easier to use PRNG algorithms interchangeably, provide random Streams.
    JDK 17
    new Random().ints()
  • Stream.toList as convenience for the most typical collection method (instead of relying on .collect(Collectors.toList()))
    JDK 16
    ListString> result =
      Stream.of("one", "two", "three").stream()
        .filter(s -> s.length() == 3)
  • Stream.mapMulti to replace each element of this stream with zero or more elements, an alternative to flatMap
    JDK 16
    Stream.of(1, 2, 3, 4)
        .mapMulti((number, downstream) -> downstream.accept(number))
        .forEach(System.out::print); // prints 1234

    → Related: Faster flatMaps with Stream::mapMulti in Java 16

  • New builder to HTTP client that specifies a header filter
    JDK 16

  • DateTimeFormatterBuilder.html#appendDayPeriodText to support other day periods than AM/PM
    JDK 16

  • Unix-domain socket channels and server socket channels
    JDK 16

  • @Serial to indicate fields and methods that are part of the serialization mechanism (e.g. serialVersionUID and readObject)
    JDK 14

  • Support Non-Volatile Mapped Byte Buffers in the FileChannel API
    JDK 14

  • Files.mismatch: find the first mismatched byte in the content of two files
    JDK 12

  • Collectors.teeing to create a Collector that is a composite of two downstream collectors
    JDK 12

  • String enhancements: indent and transform
    JDK 12

  • Standard HTTP Client featuring HTTP/2, WebSocket support and non-blocking API
    JDK 11 (Incubator 🥚 in JDK 9)
    HttpClient httpClient = HttpClient.newBuilder().build();
    HttpRequest request =
    HttpResponseString> response =
      httpClient.send(request, BodyHandlers.ofString());
  • String enhancements, like isBlank, lines, repeat and strip
    JDK 11

  • Convenience Factory Methods for Collections to ease the pain of not having collection literals
    JDK 9
    SetInteger> mySet = Set.of(1, 2, 3);
    ListInteger> myList = List.of(1, 2, 3);
    MapString, Integer> myMap = Map.of("one", 1, "two", 2);
  • Reactive Streams publish-subscribe framework for asynchronous stream processing with non-blocking backpressure
    JDK 9

  • Time-based enhancements to CompletableFuture (timeout, delay)
    JDK 9

  • More options to transform (dropWhile, takeWhile) and generate (iterate, ofNullable) streams; readonly collectors (toUnmodifiableList); optionals can be transformed to streams
    JDK 9

  • Arrays.mismatch: find the first mismatching element between two arrays
    JDK 9

  • System.Logger API providing a common mechanism to handle platform logs, allowing JDK platform classes to use the same logging framework as the application
    JDK 9

  • Stack-Walking API that allows laziness and stack-frame filtering
    JDK 9

  • Process API provides more info and control (e.g. process ID, arguments, CPU time, parent/child processes), enhance ProcessBuilder to aid the creation of process pipelines
    JDK 9

  • VarHandle API to replace the field and array related operations of java.util.concurrent.atomic and sun.misc.Unsafe in order to and provide low-level access mechamisms, e.g. atomic write.
    JDK 9

  • New combinators and lookup methods for MethodHandle
    JDK 9

  • Enhanced Deprecation policy. @Deprecated can be marked with forRemoval, which emits a new warning.
    JDK 9

  • OASIS Standard XML Catalog API to manage external resources in XMLs in a secure and performant manner
    JDK 9

  • Update JDK’s XML parser, Xerces, to version 2.11.0
    JDK 9

  • TIFF Support for Image I/O Framework
    JDK 9


  • Unicode 10.0, adding roughly 27,000 characters, 10 blocks, and more than 30 scripts
    JDK 11 (Unicode 8.0 support in JDK 9)

  • java.util.Locale and related APIs support currency type, time zone and more
    JDK 10

  • ResourceBundle loads properties files in UTF-8 instead of ISO-8859-1
    JDK 9

  • CLDR Locale Data Enabled by Default
    JDK 9

Graphics and Desktop Applications

  • Desktop features for all platforms like login/logout/lock event listener and task bar interactions
    JDK 9

  • MultiResolutionImage that makes easy to retrieve a resolution-specific image for a DPI
    JDK 9

  • HiDPI Graphics on Windows and Linux
    JDK 9

  • Enable GTK 3 on Linux for JavaFX, Swing, and AWT
    JDK 9

  • Replace @beaninfo Javadoc tags with @BeanInfo annotations for Swing
    JDK 9

  • Update GStreamer included in JavaFX/Media to version 1.4.4
    JDK 9

  • Replace the existing ICU OpenType font-layout engine with HarfBuzz
    JDK 9

Performance Improvements


  • Elastic metaspace to return unused HotSpot class-metadata memory to the operating system more promptly
    JDK 16

  • Foreign-Memory Access API to safely and efficiently use off-heap memory (Incubator 🥚)
    JDK 15 JDK 14

  • Enable dynamic archiving of classes at the end of Java application execution
    JDK 13

  • Class-Data Sharing archive of the default class list is enabled by default to improve out-of-the-box startup time
    JDK 12

  • Application Class-Data Sharing to improve startup time and reduce footprint by sharing class metadata between Java processes.
    JDK 10

  • Space-efficient, Compact Strings that stores Latin-1 only Strings more efficiently
    JDK 9

  • Code caches of profiled and non-profiled compiled code is separated, resulting in improved performance and memory footprint
    JDK 9

  • Store Interned Strings in Class-Data Sharing archives to reduce memory consumption
    JDK 9


  • New internal macOS rendering pipeline that supports Apple’s new Metal Framework for the Java 2D API, replacing the old rendering pipeline that targets OpenGL which was deprecated by Apple in macOS 10.14
    Performance comparision: JDK-8261408
    JDK 17

  • Improved intrinsics for java.lang.Math sin, cos and log functions on AArch64 processors
    JDK 11

  • Security Manager performance improvements
    JDK 9

  • Spin-Wait Hint (Thread#onSpinWait) to optimize busy-waiting style loops
    JDK 9

  • Use Marlin Renderer in Java 2D as the default graphics rasterizer instead of Pisces
    JDK 9

  • Improved GHASH and RSA performance by leveraging recently-introduced SPARC and Intel x64 CPU instructions
    JDK 9


  • Virtual Threads - lightweight user-mode threads that are cheap to create in huge numbers, making blocking APIs cool again
    JDK 21 (Preview 🔍 in JDK 20 JDK 19)
    // With OS threads, this would be very problematic
    try (var executor = Executors.newVirtualThreadPerTaskExecutor()) {
        IntStream.range(0, 10_000).forEach(i -> {
            executor.submit(() -> {
                System.out.println("" + i);
                return i;

    → Virtual Threads: An Adoption Guide - Oracle
    → Episode 29 “Helidon Níma & Virtual Threads” with Tomas Langer

  • Structured concurrency API (Preview 🔍) to define subtask relations between threads to streamline error handling and cancellation, improve reliability, and enhance observability
    JDK 21 (Incubator 🥚 in JDK 20 JDK 19)
    try (var scope = new StructuredTaskScope.ShutdownOnFailure()) {
        SupplierString>  user  = scope.fork(() -> findUser());
        SupplierInteger> order = scope.fork(() -> fetchOrder());
        scope.join()             // Join both subtasks
              .throwIfFailed();  // ... and propagate errors
        // Here, both subtasks have succeeded, so compose their results
        return new Response(user.get(), order.get());
  • Scoped Values (Preview 🔍), an alternative to ThreadLocal that allows sharing immutable data with limit visibility
    JDK 21 (Incubator 🥚 in JDK 20)

  • Thread-Local Handshakes to stop individual threads
    JDK 10

  • Improved performance of contended object monitors
    JDK 9

  • Extra space on thread stack for critical sections, mitigating the risk of a deadlock in java.util.concurrent locks in case of a stack overflow
    JDK 9

Native access

  • Foreign Function & Memory API (Preview 🔍), alternative to JNI to access native code and memory with a safe, pure Java API
    JDK 21 JDK 20 JDK 19 (Incubator 🥚 in JDK 18 JDK 17)

    import java.lang.foreign.*;
    import java.lang.invoke.*;
    Linker linker = Linker.nativeLinker();
    SymbolLookup stdlib = linker.defaultLookup();
    MethodHandle strlen = linker.downcallHandle(
      FunctionDescriptor.of(ValueLayout.JAVA_LONG, ValueLayout.ADDRESS)
    try (Arena arena = Arena.ofConfined()) {
      MemorySegment cString = arena.allocateUtf8String("Hello");
      long len = (

This post first appeared on Blog - Advanced Web Machinery, please read the originial post: here

Share the post

A categorized list of all Java and JVM features since JDK 8 to 21


Subscribe to Blog - Advanced Web Machinery

Get updates delivered right to your inbox!

Thank you for your subscription