Since the release of Java SE 8, all the developers were under the charm of the Lambdas, Streams and even there those who fell in love with Nashorn for years (yes there are somewhere in this globe 😅).. With the crazy growth of the Enterprise Development context thru Spring Boot/Cloud, Docker, Kubernetes and the unlimited number of JS frameworks, the infinite patterns and styles of architectures, many developers lost the frequency of being up-to-date with the upstream 🤪

I was one of the unsynchronized Java developers that couldn’t get up-to-date with all this crazy new comers everyday 🥺🤯 I got the idea to write a new post, to help Java developers get upToDate Quickly on the last five Java Releases 😁

Java logo Java logo

⚠️⚠️ I will try to list the most significant new features. This listing is inclusive but not exhaustive. ⚠️⚠️

Java 9 - July 27, 2017

JEP 222: jshell: The Java Shell (Read-Eval-Print Loop)

The JShell API and tool will provide a way to interactively evaluate declarations, statements, and expressions of the Java programming language within the JShell state. The JShell state includes an evolving code and execution state. To facilitate rapid investigation and coding, statements and expressions need not occur within a method, and variables and method need not occur within a class.

The jshell tool will be a command-line tool with features to ease interaction including: a history with editing, tab-completion, automatic addition of needed terminal semicolons, and configurable predefined imports and definitions.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
$ jshell
|  Welcome to JShell -- Version 9
|  For an introduction type: /help intro

jshell> int x = 2
x ==> 2

jshell> int y = 3
y ==> 3

jshell> System.out.println("x + y = "+ (x+y));
x + y = 5

jshell> /exit
|  Goodbye

JSR 376: Java Platform Module System (JSR 376)

This is the biggest new feature of Java 9.

The primary goals of this project are to:

  • Make it easier for developers to construct and maintain libraries and large applications;
  • Improve the security and maintainability of Java SE Platform Implementations in general, and the JDK in particular;
  • Enable improved application performance;
  • Enable the Java SE Platform, and the JDK, to scale down for use in small computing devices and dense cloud deployments.

To achieve these goals, the JCP designed and implemented a standard module system for the Java 9 and applied that system to the Platform itself and to its Reference Implementation, JDK 9. The module system is powerful enough to modularize the JDK and other large legacy code bases, yet is still approachable by all developers.

A Module is a group of Java classes and resources packaged together with a descriptor file called module-info.java.

For sure, this JSR cannot be covered in this quick post. There are many books dedicated for this huge new feature:

Private methods in Interfaces

Since Java 8, we have a new feature: Functional Interface which is an interface class that contains only a single abstract (unimplemented) method. A functional interface can contain default public and static methods have an implementation, in addition to the single unimplemented method. Starting from Java 9, these methods can be private.

For example:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
@FunctionalInterface
public interface MyFunctionalInterface {
    Logger log = Logger.getLogger(MyFunctionalInterface.class.getName());

    void find();

    default void init() {
        this.logOperation("init");
    }

    private void logOperation(String operation) {
        log.info("Operation [" + operation + "] is called.");
    }
}

JEP 110: the new HTTP/2 Client

Java 9 comes with a brand new native HTTP client that supports HTTP/2 with backward compatibility with the previous versions of HTTP. With this new HTTP client, we will not need additional libraries to call a REST API:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
public static void main(String[] args) throws Exception {
    String url = "https://api.exchangeratesapi.io/latest";

    HttpClient client = HttpClient.newHttpClient();
    HttpRequest httpRequest = HttpRequest.newBuilder(new URI(url))
            .header("Accept", "application/json")
            .header("Content-Type", "application/json")
            .GET()
            .build();

    HttpResponse<String> httpResponse = client.send(httpRequest, HttpResponse.BodyHandlers.ofString());
    String jsonResponse = httpResponse.body();

    System.out.println(jsonResponse);
}

The code listed here was updated after the release Java 11: my actual runtime 😁

Enhanced Try-with-Resources:

Java 7 brought a new feature called Try-with-Resource statement which was a very useful feature for handling/closing a resource when an exception occurs. This Try-with-Resource statement got updated in Java 9 to be more simplified and less verbose. Let’s take this example:

The Java 7 version:

1
2
3
4
5
6
7
8
9
public static void main(String[] args) throws Exception {
    FileOutputStream fileOutputStream = new FileOutputStream("document.txt");
    try(FileOutputStream fileOutputStream2 = fileOutputStream){
        String content = "Hello World from Java 7";
        fileOutputStream2.write(content.getBytes());
    }catch(Exception e) {
        log.error(e.getMessage());
    }
}

The Java 9 version:

1
2
3
4
5
6
7
8
9
public static void main(String[] args) throws Exception {
    FileOutputStream fileOutputStream = new FileOutputStream("document.txt");
    try (fileOutputStream) {
        String content = "Hello World from Java 9";
        fileOutputStream.write(content.getBytes());
    } catch (Exception e) {
       log.error(e.getMessage());
    }
}

JEP 102: Process API Updates

The Process API got also updated in Java 9: new classes and methods are introduced to ease the controlling and managing of OS processes.

For example, to show the current PID:

1
System.out.println("Current PID: " + ProcessHandle.current().getPid());

JEP 269: Convenience Factory Methods for Collections

Java 9 has introduced some convenient factory methods to create Immutable List, Set, Map and Map.Entry objects. These utility methods are used to create empty or non-empty Collection objects. Let’s take the example of creating an immutable List:

Before Java 9:

1
2
3
4
5
List<String> letters = new ArrayList<>();
letters.add("A");
letters.add("B");
letters.add("C");
List<String> immutableLettersList = Collections.unmodifiableList(letters);

In Java 9:

1
 List<String> immutableLettersList = List.of("A","B","C");

Enhanced Optional class

The Optional class got some new methods in Java 9:

  • ifPresentOrElse(): If a value is present, performs the given action with the value, otherwise performs the given empty-based action.

  • or(): If a value is present, returns an Optional describing the value, otherwise returns an Optional produced by the supplying function.

  • stream(): If a value is present, returns a sequential Stream containing only that value, otherwise returns an empty Stream.

Enhanced Stream API

In Java 9, we got four new methods to java.util.Stream interface:

  • takeWhile(): Returns, if this stream is ordered, a stream consisting of the longest prefix of elements taken from this stream that match the given predicate. Otherwise returns, if this stream is unordered, a stream consisting of a subset of elements taken from this stream that match the given predicate.
  • dropWhile(): Returns, if this stream is ordered, a stream consisting of the remaining elements of this stream after dropping the longest prefix of elements that match the given predicate. Otherwise returns, if this stream is unordered, a stream consisting of the remaining elements of this stream after dropping a subset of elements that match the given predicate.
  • ofNullable(): Returns a sequential Stream containing a single element, if non-null, otherwise returns an empty Stream.
  • iterate(): Returns a sequential ordered Stream produced by iterative application of the given next function to an initial element, conditioned on satisfying the given hasNext predicate. The stream terminates as soon as the hasNext predicate returns false.

For example: this code will show the numbers less than 50:

1
2
3
4
5
Stream<Integer> numbersStream = Stream.iterate(1, n -> n * 10)
                                      .limit(10);

numbersStream.takeWhile(num -> num < 50)
             .forEach(System.out::println);

Enhanced Diamond operator

Java 9 improved the use of diamond operator and allows us to use the diamond operator with anonymous inner classes. Let’s take this example, which was not possible to run before Java 9:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
abstract class Calculator<T> {
    abstract T add(T num, T num2);
    abstract T sub(T num, T num2);
    abstract T mult(T num, T num2);
    abstract T div(T num, T num2);
}

public static void main(String[] args) {

    Calculator<Integer> obj = new Calculator<>() {
        Integer add(Integer x, Integer y) {
            return x + y;
        }

        Integer sub(Integer x, Integer y) {
            return x - y;
        }

        Integer mult(Integer x, Integer y) {
            return x * y;
        }

        Integer div(Integer x, Integer y) {
            return x / y;
        }
    };

    Integer sum = obj.add(2, 4);
    System.out.println(sum);
    Integer sub = obj.sub(100, 10);
    System.out.println(sub);
    Integer mult = obj.mult(5, 6);
    System.out.println(mult);
    Integer div = obj.div(100, 3);
    System.out.println(div);
}

JEP 266: More Concurrency Updates

Java 9 comes with some changes to the CompletableFuture class to solve some problems raised since its introduction in Java 8. Now, it supports delays and timeouts, and a better support for subclassing.

The new class methods:

  1. Executor defaultExecutor()
  2. CompletableFuture<U> newIncompleteFuture()
  3. CompletableFuture<T> copy()
  4. CompletionStage<T> minimalCompletionStage()
  5. CompletableFuture<T> completeAsync(Supplier<? extends T> supplier, Executor executor)
  6. CompletableFuture<T> completeAsync(Supplier<? extends T> supplier)
  7. CompletableFuture<T> orTimeout(long timeout, TimeUnit unit)
  8. CompletableFuture<T> completeOnTimeout(T value, long timeout, TimeUnit unit)

The new static methods:

  1. Executor delayedExecutor(long delay, TimeUnit unit, Executor executor)
  2. Executor delayedExecutor(long delay, TimeUnit unit)
  3. <U> CompletionStage<U> completedStage(U value)
  4. <U> CompletionStage<U> failedStage(Throwable ex)
  5. <U> CompletableFuture<U> failedFuture(Throwable ex)

The full list of the Java 9 new features.

Java 10 - March 20, 2018

JEP 286: Local-Variable Type Inference

Local-Variable Type Inference is the biggest new feature in Java 10 that many many developers are waiting for 🥳 It adds type inference to declarations of local variables with initializers. Now, we can do this in Java 😁

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
public static void main(String[] args) {
    var numbers = List.of(1, 2, 3, 4, 5);
    for (var number : numbers) {
        System.out.println(number);
    }
    
    var letters = List.of("A", "B", "C");
    for (var letter : letters) {
        System.out.println(letter);
    }
}

In this code:

  • numbers will be inferred as ArrayList<Integer>
  • number will be inferred as Integer
  • letters will be inferred as ArrayList<String>
  • letter will be inferred as String

Java Improvements for Docker Containers

Java 10 came with many new features to improve the execution and configurability of Java running in Docker containers. I covered this great feature in a dedicated blog post: Playing with the JVM inside Docker Containers.

JEP 304: Garbage-Collector Interface

Java 10 improves the source code isolation of different garbage collectors by introducing a clean garbage collector (GC) interface that helps:

  • Better modularity for HotSpot internal GC code
  • Make it simpler to add a new GC to HotSpot without perturbing the current code base
  • Make it easier to exclude a GC from a JDK build

JEP 307: Parallel Full Garbage Collector for G1

Since Java 9, G1 garbage collector is the default garbage collector. The JEP 307 improves G1 worst-case latencies by making the full GC parallel. The G1 garbage collector is designed to avoid full collections, but when the concurrent collections can’t reclaim memory fast enough a fall back full GC will occur. The old implementation of the full GC for G1 used a single threaded mark-sweep-compact algorithm. With JEP 307 the full GC has been parallelized and now use the same amount of parallel worker threads as the young and mixed collections.

JEP 310: Application Class-Data Sharing

The goal of this feature is to improve the startup footprint, extends the existing Class-Data Sharing (“CDS”) feature to allow application classes to be placed in the shared archive.

Class-Data Sharing, introduced in JDK 5, allows a set of classes to be pre-processed into a shared archive file that can then be memory-mapped at runtime to reduce startup time. It can also reduce dynamic memory footprint when multiple JVMs share the same archive file.

Currently CDS only allows the bootstrap class loader to load archived classes. Application CDS allows the built-in system class loader, the built-in platform class loader, and custom class loaders to load archived classes.

Specify the -XX:+UseAppCDS command-line option to enable class data sharing for the system class loader, the platform class loader, and other user-defined class loaders.

JEP 312: Thread-Local Handshakes

This internal JVM feature aims to improve performance. A handshake operation is a callback that is executed for each JavaThread while that thread is in a safepoint state. The callback is executed either by the thread itself or by the VM thread while keeping the thread in a blocked state.

This feature provides a way to execute a callback on threads without performing a global VM safepoint. Make it both possible and cheap to stop individual threads and not just all threads or none.

JEP 313: Remove the Native-Header Generation Tool (javah)

Tool javah has been removed from Java 10 which generated C headers and source files which were required to implement native methods – now, javac -h can be used instead.

JEP 314: Additional Unicode Language-Tag Extensions

It’s goal is to enhance java.util.Locale and related APIs to implement additional Unicode extensions of BCP 47 language tags.

Support for BCP 47 language tags was was initially added in Java 7, with support for the Unicode locale extension limited to calendars and numbers. This JEP will implement more of the extensions specified in the latest LDML specification, in the relevant JDK classes.

This JEP will add support for the following additional extensions:

  • cu (currency type)
  • fw (first day of week)
  • rg (region override)
  • tz (time zone)

Related APIs which got modified are:

  • java.text.DateFormat::get*Instance
  • java.text.DateFormatSymbols::getInstance
  • java.text.DecimalFormatSymbols::getInstance
  • java.text.NumberFormat::get*Instance
  • java.time.format.DateTimeFormatter::localizedBy
  • java.time.format.DateTimeFormatterBuilder::getLocalizedDateTimePattern
  • java.time.format.DecimalStyle::of
  • java.time.temporal.WeekFields::of
  • java.util.Calendar::getFirstDayOfWeek
  • java.util.Calendar::getMinimalDaysInWeek
  • java.util.Currency::getInstance
  • java.util.Locale::getDisplayName
  • java.util.spi.LocaleNameProvider

JEP 317: Experimental Java-Based JIT Compiler

This JEP will enable Graal: the Java-based Just-in-Time compiler, to be used as an experimental JIT compiler on the Linux/x64 platform.

Graal was introduced in Java 9. It’s an alternative to the JIT compiler which we have been used to, which was written in C++. It’s an addon to the JVM, which means that the JIT compiler is not tied to JVM and it can be dynamically plugged in and replaced with any another plugin. It also brings :

  • Ahead of Time (AOT) compilation in Java Applications
  • the support of polyglot language interpretation

JEP 319: Root Certificates

This JEP will open-source the root certificates in Oracle’s Java SE Root CA program in order to make OpenJDK builds more attractive to developers, and to reduce the differences between those builds and Oracle JDK builds. This means that both Oracle JDK & OpenJDK binaries will be functionally the same.

JEP 322: Time-Based Release Versioning

This JEP will revise the version-string scheme of the Java SE Platform and the JDK, and related versioning information, for present and future time-based release models. Especially that since Java 10, we intend to ship new releases of the Java SE Platform and the JDK on a strict, six-month cadence.

The new format will be:

[1-9][0-9]*((.0)*.[1-9][0-9]*)*

The sequence may be of arbitrary length but the first four elements are assigned specific meanings, as follows:

$FEATURE.$INTERIM.$UPDATE.$PATCH

  • $FEATURE — The feature-release counter, incremented for every feature release regardless of release content. Features may be added in a feature release; they may also be removed, if advance notice was given at least one feature release ahead of time. Incompatible changes may be made when justified. (Formerly $MAJOR.)
  • $INTERIM — The interim-release counter, incremented for non-feature releases that contain compatible bug fixes and enhancements but no incompatible changes, no feature removals, and no changes to standard APIs. (Formerly $MINOR.)
  • $UPDATE — The update-release counter, incremented for compatible update releases that fix security issues, regressions, and bugs in newer features. (Formerly $SECURITY, but with a non-trivial incrementation rule.)
  • $PATCH — The emergency patch-release counter, incremented only when it’s necessary to produce an emergency release to fix a critical issue. (Using an additional element for this purpose minimizes disruption to both developers and users of in-flight update releases.)

JEP 296: Consolidate the JDK Forest into a Single Repository

For many years, the full JDK code base has been splitted into numerous Mercurial repositories. In Java 9, there are eight repos:

  • root
  • corba,
  • hotspot
  • jaxp
  • jaxws
  • jdk
  • langtools
  • nashorn

The individual repos don’t have a development cycle separate from the JDK as a whole; all the repos advance in lockstep with the JDK promotion cycle. The multiplicity of repos presents a larger than necessary barrier to entry to new developers and has lead to workarounds such as the “get source” script.

Starting from Java 10, the numerous repositories of the JDK forest will be combined into a single repository in order to simplify the development.

The full list of the Java 10 new features.

Java 11 - September 25, 2018

JEP 330: Launch Single-File Source-Code Programs

One major change is that you don’t need to compile the java source file with javac tool first. You can directly run the file with java command and it will implicitly compile before running.

New String methods

Java 11 brings new methods in the String class:

  • lines(): Returns a stream of lines extracted from this string, separated by line terminators.
  • isBlank(): Returns true if the string is empty or contains only white spaces, otherwise false.
  • repeat(): Returns a string whose value is the concatenation of this string repeated count times.
  • strip(): Returns a string whose value is this string, with all leading and trailing white space removed.
  • stripLeading(): Returns a string whose value is this string, with all leading white space removed.
  • stripTrailing(): Returns a string whose value is this string, with all trailing white space removed.
  • lines(): Returns a stream of lines extracted from this string, separated by line terminators.

JEP 323: Local-Variable Syntax for Lambda Parameters

This JEP allows the keyword var to be used when declaring the formal parameters of implicitly typed lambda expressions. For example, we can do this in Java 11:

(var x, var y) -> x.process(y)

New methods added in java.nio.file.Files

Java 11 introduced new methods in the java.nio.file.Files class:

  • readString(): Reads all content from a file into a string, decoding from bytes to characters.
  • writeString(): Write a CharSequence to a file.
  • isSameFile(): Tests if two paths locate the same file.

Working example using these new methods:

1
2
3
4
5
6
7
8
9
public static void main(String[] args) throws IOException {
    Path tmpFilePath = Files.writeString(Files.createTempFile("test", ".txt"), "Hello World");
    System.out.println("File name: [" + tmpFilePath.toUri() + "]");
    String content = Files.readString(tmpFilePath);
    System.out.println("File content: [" + content + "]");
    Path anOtherTmpFilePath = Files.createTempFile("test", ".txt");
    boolean sameFile = Files.isSameFile(tmpFilePath, anOtherTmpFilePath);
    System.out.println("Are two tmp files equals? : " + sameFile);
}

This sample code will have an output similar to:

File name: [file:///var/folders/0v/m4k0wtm521xfsmwyfr1_zslm0000gn/T/test303123248058134079.txt] File content: [Hello World] Are two tmp files equals? : false

New ToArray() method in the Collection Class

The new toArray(java.util.function.IntFunction): Returns an array containing all of the elements in this collection, using the provided generator function to allocate the returned array. For example:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
public static void main(String[] args) {

    List<String> letters = new ArrayList<>();
    letters.add("A");
    letters.add("B");
    letters.add("C");
    letters.add("D");

    //Before Java 11
    String[] lettersArray = letters.toArray(new String[letters.size()]);

    //Since Java 11
    String[] anOtherLettersArray = letters.toArray(String[]::new);
}

New isEmpty() method in the Optional class

The method Optional.isEmpty() returns true if the value of any object is null and else returns false. This can be done in Java 11:

1
2
3
4
public static void main(String[] args) {
    Optional notSure = Optional.ofNullable(null);
    System.out.println(notSure.isEmpty());
}

JEP 321: HTTP Client (Standard)

Java 11 has a native HTTP Client supporting WebSocket connections! The client was already introduced in Java 9. But in the Java 11, the HTTP Client API get standardized 🥳

Here is a Java 11 WebSocket example:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
@Slf4j
public class Main {
    public static void main(String[] args) throws InterruptedException {

        ExecutorService executor = Executors.newFixedThreadPool(4);

        HttpClient httpClient = HttpClient.newBuilder().executor(executor).build();
        WebSocket.Builder webSocketBuilder = httpClient.newWebSocketBuilder();
        WebSocket webSocket = webSocketBuilder.buildAsync(URI.create("wss://echo.websocket.org"), 
            new WebSocket.Listener() {
                @Override
                public void onOpen(WebSocket webSocket) {
                    log.info("CONNECTED");
                    webSocket.sendText("This is a message", true);
                    WebSocket.Listener.super.onOpen(webSocket);
                }

                @Override
                public CompletionStage<?> onText(WebSocket webSocket, CharSequence data, boolean last) {
                    log.info("onText received with data " + data);
                    if (!webSocket.isOutputClosed()) {
                        webSocket.sendText("This is a message", true);
                    }
                    return WebSocket.Listener.super.onText(webSocket, data, last);
                }

                @Override
                public CompletionStage<?> onClose(WebSocket webSocket, int statusCode, String reason) {
                    log.info("Closed with status " + statusCode + ", reason: " + reason);
                    executor.shutdown();
                    return WebSocket.Listener.super.onClose(webSocket, statusCode, reason);
                }
        }).join();
        log.info("WebSocket created");
        Thread.sleep(1000);
        webSocket.sendClose(WebSocket.NORMAL_CLOSURE, "ok").thenRun(() -> log.info("Sent close"));
    }
}

JEP 328: Flight Recorder

Flight Recorder is a profiling tool used to gather diagnostics and profiling data from a running Java application. Its performance overhead is negligible and that’s why it can be used in production.

Flight Recorder records events originating from applications, the JVM and the OS. Events are stored in a single file that can be attached to bug reports and examined by support engineers, allowing after-the-fact analysis of issues in the period leading up to a problem. Tools can use an API to extract information from recording files.

JEP 331: Low-Overhead Heap Profiling

This JEP provides a way to get information about Java object heap allocations from the JVM that:

  • Is low-overhead enough to be enabled by default continuously
  • Is accessible via a well-defined, programmatic interface
  • Can sample all allocations
  • Can be defined in an implementation-independent way (i.e., not limited to a particular GC algorithm or VM implementation)
  • Can give information about both live and dead Java objects.

JEP 335: Deprecate the Nashorn JavaScript Engine

This JEP is coming to deprecate the Nashorn JavaScript Engine introduced in Java 8, with the intent to remove them in a future release 😱

The full list of the Java 11 new features.

Java 12 - March 19, 2019

JEP 325: Switch Expressions (Preview)

I think this is the most important feature coming in Java 12. This is a preview feature that extends the switch statement so that it can be used as either a statement or an expression. Let’s say what’s new:

  • There is no need for break statement - your case will not be falling into the next case.
  • We can define multiple constants in the same label.
  • default case is now compulsory in Switch Expressions.
  • break is used in Switch Expressions to return values from a case itself.

These changes will simplify everyday coding 🤩 for example, instead of doing this before Java 12:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
public class Main {
    public static void main(String[] args) {

        System.out.println("Enter your product number");
        String choice = new Scanner(System.in).nextLine();

        String price;

        switch (choice) {
            case "1":
            case "3":
            case "7":
                price = "5$";
                break;
            case "2":
            case "4":
            case "9":
                price = "15$";
                break;
            case "5":
            case "6":
            case "8":
                price = "35$";
                break;
            default:
                price = "Unknown product..";
                break;
        }

        System.out.println("Price is: " + price);
        System.out.println("Thank you for your visit");
    }
}

We can now do it in the easy way:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
public class Main {
    public static void main(String[] args) {

        System.out.println("Enter your product number");
        String choice = new Scanner(System.in).nextLine();

        String price = switch (choice) {
            case "1", "3", "7" -> "5$";
            case "2", "4", "9" -> "15$";
            case "5", "6", "8" -> "35$";
            default -> "Unknown product..";
        };

        System.out.println("Price is: " + price);
        System.out.println("Thank you for your visit");
    }
}

As it’s a preview feature, you will need to add --enable-preview parameter to the javac command in order to compile this code under JDK 12.

JEP 230: Microbenchmark Suite

This JEP adds a basic suite of microbenchmarks to the JDK source code, and make it easy to run existing microbenchmarks and create new ones. It is based on the Java Microbenchmark Harness (JMH).

Let’s test JMH; first of all, you can generate the sample project using the command:

1
2
3
4
5
6
7
$ mvn archetype:generate \
    -DinteractiveMode=false \
    -DarchetypeGroupId=org.openjdk.jmh \
    -DarchetypeArtifactId=jmh-java-benchmark-archetype \
    -DgroupId=org.sample \
    -DartifactId=test \
    -Dversion=1.0

This command will create a Maven project, containing only one class called org.sample.MyBenchmark. We will use it to benchmark our code:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
public class MyBenchmark {

    @Benchmark
    public void testMethod() {
        System.out.println("Enter your product number");
        String choice = "5";

        String price;

        switch (choice) {
            case "1":
            case "3":
            case "7":
                price = "5$";
                break;
            case "2":
            case "4":
            case "9":
                price = "15$";
                break;
            case "5":
            case "6":
            case "8":
                price = "35$";
                break;
            default:
                price = "Unknown product..";
                break;
        }

        System.out.println("Price is: " + price);
        System.out.println("Thank you for your visit");
    }
}

Now, compile the project using: mvn clean install - this command will build two jars:

  • test-1.0.jar 👉 the compiled project

  • benchmarks.jar 👉 the JMH Jar file 😁 to run the benchmarking, run this jar using the java -jar target/benchmarks.jar command.

The output of running the benchmarks:

WARNING: An illegal reflective access operation has occurred
WARNING: Illegal reflective access by org.openjdk.jmh.util.Utils (file:/Users/nebrass/temp/test/target/benchmarks.jar) to field java.io.Console.cs
WARNING: Please consider reporting this to the maintainers of org.openjdk.jmh.util.Utils
WARNING: Use --illegal-access=warn to enable warnings of further illegal reflective access operations
WARNING: All illegal access operations will be denied in a future release
# JMH version: 1.22
...
# VM options: <none>
# Warmup: 5 iterations, 10 s each
# Measurement: 5 iterations, 10 s each
# Timeout: 10 min per iteration
# Threads: 1 thread, will synchronize iterations
# Benchmark mode: Throughput, ops/time
# Benchmark: org.sample.MyBenchmark.testMethod

# Run progress: 0,00% complete, ETA 00:08:20
# Fork: 1 of 5
# Warmup Iteration   1: Enter your product number
...
80421,846 ops/s

Result "org.sample.MyBenchmark.testMethod":
  60122,841 Âą(99.9%) 18195,223 ops/s [Average]
  (min, avg, max) = (21484,177, 60122,841, 82116,041), stdev = 24290,103
  CI (99.9%): [41927,618, 78318,065] (assumes normal distribution)

# Run complete. Total time: 00:08:22

REMEMBER: The numbers below are just data. To gain reusable insights, you need to follow up on
why the numbers are the way they are. Use profilers (see -prof, -lprof), design factorial
experiments, perform baseline and negative tests that provide experimental control, make sure
the benchmarking environment is safe on JVM/OS/HW level, ask for reviews from the domain experts.
Do not assume the numbers tell you what you want them to tell.

Benchmark                Mode  Cnt      Score       Error  Units
MyBenchmark.testMethod  thrpt   25  60122,841 Âą 18195,223  ops/s

JEP 189: Shenandoah: A Low-Pause-Time Garbage Collector (Experimental)

This feature adds a new garbage collection (GC) algorithm named Shenandoah which reduces GC pause times by doing evacuation work concurrently with the running Java threads. Pause times with Shenandoah are independent of heap size, meaning you will have the same consistent pause times whether your heap is 200 MB or 200 GB.

New Teeing() method in Collectors Class

Java 12 introduces a new teeing collector in the Collectors class. This collector forwards its input to two other collectors before merging their results with a function.

For example:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
public class Main {
    public static void main(String[] args) {
        List<Integer> numbers =
                IntStream.range(1, 100)
                        .boxed()
                        .collect(Collectors.toList());

        Double average =
                numbers.stream()
                        .collect(Collectors.teeing(
                                Collectors.summingDouble(i -> i),
                                Collectors.counting(),
                                (sum, n) -> sum / n));
        System.out.println(average);
    }
}

JEP 341 Default CDS Archives

This JEP enhances the build process to generate a Class Data-Sharing (CDS) archive, using the default class list, on 64-bit platforms. This aims to improve startup time. From Java 12, CDS is by default ON.

JEP 344 : Abortable Mixed Collections for G1

This JEP bring improvements in G1 efficiency include making G1 mixed collections abortable if they might exceed the defined pause target. This is done by splitting the mixed collection set into mandatory and optional. Thus the G1 collector can prioritize on collecting the mandatory set first to meet the pause time goal.

New MISMATCH() method in the java.nio.files class

Based on the javadoc: Finds and returns the position of the first mismatched byte in the content of two files, or -1L if there is no mismatch. For example:

1
2
3
4
5
6
7
8
public class Main {
    public static void main(String[] args) throws IOException {
        Path tmpFilePath = Files.writeString(Files.createTempFile("test", ".txt"), "Hello World");
        Path anOtherTmpFilePath = Files.writeString(Files.createTempFile("test", ".txt"), "HelloWorld");
        long mismatch = Files.mismatch(tmpFilePath, anOtherTmpFilePath);
        System.out.println("Mismatch: [" + mismatch + "]");
    }
}

This code will output Mismatch: [5] as the first different character between "Hello World" and "HelloWorld" will be on the 5th position.

JEP 305: Pattern Matching for instanceof (Preview)

This is a preview of a new feature. This JEP will enhance the Java programming language with pattern matching for the instanceof operator. Pattern matching allows common logic in a program, namely the conditional extraction of components from objects, to be expressed more concisely and safely.

Before Java 12:

1
2
3
4
if (obj instanceof String) {
    String s = (String) obj;
    // use s
}

The new way is :

1
2
3
if (obj instanceof String s) {
    // can use s directly here
}

This will improve the readability of the code 😁

New methods in the String class

Java 12 introduced many new useful methods:

  • indent(): Adjusts the indentation of each line of this string based on the value of n, and normalizes line termination characters.
  • transform(): This method allows the application of a function to this string.
  • describeConstable(): Returns an Optional containing the nominal descriptor for this instance, which is the instance itself.
  • resolveConstantDesc(): Resolves this instance as a ConstantDesc, the result of which is the instance itself.

The full list of the Java 12 new features.

Java 13 - September 17, 2019

JEP 354: Switch Expressions (Preview)

Switch expressions were proposed in December 2017 by JEP 325. They were targeted to JDK 12 in August 2018 as a preview feature. Feedback was sought initially on the design of the feature, and later on the experience of using switch expressions and the enhanced switch statement. Based on that feedback, this JEP makes one change to the feature:

To yield a value from a switch expression, the break with value statement is dropped in favor of a yield statement.

This Java 12 code:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
public class Main {
    public static void main(String[] args) {

        System.out.println("Enter your product number");
        String choice = new Scanner(System.in).nextLine();

        String price = switch (choice) {
            case "1", "3", "7" -> "5$";
            case "2", "4", "9" -> "15$";
            case "5", "6", "8" -> "35$";
            default -> "Unknown product..";
        };

        System.out.println("Price is: " + price);
        System.out.println("Thank you for your visit");
    }
}

Can be written in Java 13 to be like:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
public class Main {
    public static void main(String[] args) {

        System.out.println("Enter your product number");
        String choice = new Scanner(System.in).nextLine();

        String price = switch (choice) {
            case "1", "3", "7" :
                yield "5$";
            case "2", "4", "9" :
                yield "15$";
            case "5", "6", "8" :
                yield "35$";
            default :
                yield "Unknown product..";
        };

        System.out.println("Price is: " + price);
        System.out.println("Thank you for your visit");
    }
}

⚠️⛔️⚠️⛔️ The Value Break is no more compilable in Java 13:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
public class Main {
    public static void main(String[] args) {

        System.out.println("Enter your product number");
        String choice = new Scanner(System.in).nextLine();

        String price = switch (choice) {
            case "1", "3", "7" :
                break "5$";
            case "2", "4", "9" :
                break "15$";
            case "5", "6", "8" :
                break "35$";
            default :
                break "Unknown product..";
        };

        System.out.println("Price is: " + price);
        System.out.println("Thank you for your visit");
    }
}

As it’s a preview feature, you will need to add --enable-preview parameter to the javac command in order to compile this code under JDK 13.

JEP 355: Text Blocks (Preview)

Add text blocks to the Java language. A text block is a multi-line string literal that avoids the need for most escape sequences, automatically formats the string in a predictable way, and gives the developer control over format when desired.

This feature will improve the readability of the code and will remove the Strings boilerplate that hurt the developers when dealing with multilines Strings.

For example:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
public class Main {
    public static void main(String[] args) {
        String value = "line 1\n" +
                "line 2\n" +
                "line 3\n";

        String multiLineValue = """
                line 1
                line 2
                line 3
                """;

        System.out.println(value.equals(multiLineValue));
    }
}

This is a preview language feature in JDK 13, you will need to add --enable-preview parameter to the javac command in order to compile this code.

New Methods in THE String Class

There are three new methods in the String class that complement the Text Blocks feature:

  • formatted(): Formats using this string as the format string, and the supplied arguments.
  • stripIndent(): Returns a string whose value is this string, with incidental white space removed from the beginning and end of every line.
  • translateEscapes(): Returns a string whose value is this string, with escape sequences translated as if in a string literal.

New Factory methods in the FileSystems class

This JEP introduces three new methods in the FileSystems class to make it easier to use file system providers, which treats the contents of a file as a file system.

  • newFileSystem​(Path path): Constructs a new FileSystem to access the contents of a file as a file system.
  • newFileSystem​(Path path, Map<String,​?> env): Constructs a new FileSystem to access the contents of a file as a file system.
  • newFileSystem​(Path path, Map<String,​?> env, ClassLoader loader): Constructs a new FileSystem to access the contents of a file as a file system.

JEP 353: Reimplement the Legacy Socket API

The underlying implementation of the java.net.Socket and java.net.ServerSocket APIs have been rewritten. The new implementation, NioSocketImpl, is a drop-in replacement for PlainSocketImpl.

It uses java.util.concurrent locks rather than synchronized methods. If you want to use the legacy implementation, use the java option -Djdk.net.usePlainSocketImpl.

JEP 350: Dynamic CDS Archives

This JEP enhanced the JEP 310 Application Class-Data Sharing which was introduced in Java 10, by simplifying the process of creating CDS archives.

The CDS archives will be created if the program exists with -XX:ArchiveClassesAtExit

1
$ java -XX:ArchiveClassesAtExit=hello.jsa -cp hello.jar Hello

To run the program with the CDS archives above:

1
$ java -XX:SharedArchiveFile=hello.jsa -cp hello.jar Hello

The idea behind Class Data Sharing (CDS) is a feature to improve startup performance by creating class-data archive once and then reuse it, so that the JVM need not recreate it again.

JEP 351: ZGC: Uncommit Unused Memory

This JEP has enhanced ZGC to return unused heap memory to the operating system. The Z Garbage Collector was introduced in Java 11. It adds a short pause time before the heap memory cleanup. But, the unused memory was not being returned to the operating system. This was a concern for devices with small memory footprint such as IoT and microchips. Now, it has been enhanced to return the unused memory to the operating system.

The full list of the Java 13 new features.

Final Words

As you see, Java is bringing a large number of new features and APIs. And it will continue to deliver incremental evolutions of the language, ensuring it remains the most popular and the most wonderful programming language on the planet 😍