Oracle Groundbreakers Ambassador Java Champions
Nortal Logo

Effective Java SE 9 through 19 APIs & Language features, that make your life easier.

Mohamed Taman
Solutions Architect @Nortal MEA,
Java Champion, Belgrade, Serbia.

Me, I, and Myself


  • Chief Solutions Architect
    Works for Nortal Serbia & Consultant @Ananas.rs.
    International Speaker & Author. Egyptian, and lives in Belgrade, Serbia.

  • A Java Champion, Oracle ACE, and Jakarta EE Ambassador. Web / Cloud / Spring / Mobile / Big Data / IoT / Blockchain / DevOps, JCP, 2013 - 2015 Duke Award winner 3 times, 2013 JCP award winner.

You can catch me (🀝)

here πŸ‘‡



Or google πŸ•΅ me "Mohamed Taman"

Java History πŸ›£

Java history

Image source from: The arrival of Java 19

Big change (Modularity πŸ“¦ )

“ Module bundle together one or more packages, and offer stronger encapsulation than jars. ”

  • Allow scaled down runtime JAR → IoT, Micro-services, Embedded, Cloud.
  • Stronger: In a module: public is no longer public to others.


For more, here is my tutorial @IBM Developer:
Java 9+ modularity: The theory and motivations behind modularity.

Jigsaw project goals

πŸ₯…

  • Modular JDK
  • Modular Java Source Code
  • Modular Runtime Images
  • Encapsulate Java Internal APIs
  • Java Platform Module System


For more, here is my two tutorials @IBM Developer:
Java 9+ modularity: Module basics and rules.
Java 9+ modularity: How to design packages and create modules, Part 1, and 2.

Tools 🧰 for ease of code migrations

  • List built-in modules: java --list-modules
  • Find dependencies:    jdeps -jdkinternals app.jar
  • Find deprecations:     jdeprscan app.jar


For more, here is my tutorial @IBM Developer:
Java 9+ modularity: The difficulties and pitfalls of migrating from Java 8 to Java 9+.

The New Six Month Release Cadence and LTS
🏎


LTS πŸŽ— (Long-Term-Support)

Each 2 years we will have an LTS Release.

Java SE 11, is the

🧹
for Java jungle...

For the first time, Java 12

introduces a preview language feature

πŸ€”

Agenda

  1. What is new?
  2. Explore new language features.
  3. Explore most of new & Improved APIs.
  4. Farewell to APIs has gone forever.

No more JRE available out there! 😱

  • JRE installation package is gone, since Java SE 11.
  • jlink tool is here, to generate our custom JRE.

What is jlink ?

Linker

jlink can be used to link a set of modules, along with their transitive dependences, to create a custom modular run-time image.

New learning πŸ‘©πŸΌβ€πŸ« tool added to the stack.

Java Shell REPL tool: jshell - Java 9


For more, here is my two tutorials @IBM Developer:
Java theory and practice: Interactive Java programming (REPL) with JShell 12, Part 1, and 2.

Running .java old days

Run .java with Java - Java 11


For more, here is my tutorial @IBM Developer:
Java theory and practice: Run single-file source code programs without compilation.

Java SE language features

πŸŽ‰πŸŽŠ

New var type - Java 10

For more, here is my tutorial @InfoQ:
Explore the New Java 10 β€œvar” Type: An Introduction and Hands-on Tutorial.

Local-variable (var) Syntax for Lambda Parameters - Java 11

(String a, String b) -> a.concat(b)
( a, b) -> a.concat(b)
(var a, var b) -> a.concat(b)
Because annotations needs a type
(@Nullable var a, @Nonnull var b) -> a.concat(b)

Shell scripting with Java: Shebang files - Java 11

Run Java Shebang file

Save this code in a file named dirlist without any extension and then mark it as executable:

mohamed_taman:code$ chmod +x dirlist

HTTP & WebSocket Client module

The evolution of HttpClient and WebSocket API

  • The latest HttpClient and WebSocket APIs originally shipped with JDK 9 under the Java Enhancement Proposal JEP 110 as part of an incubator module named jdk.incubator.httpclient.

  • They were re-incubated again in JDK 10, but finally became standardized in a module named java.net.http and brought into the mainstream in JDK 11 under JEP 321.

  • This API provides a high-level client interface to HTTP (versions 1.1 and 2) and low-level client interfaces for the WebSocket API: HttpClient, HttpRequest, HttpResponse, and WebSocket.

HTTP Client module

Demonstrating how all three APIs work together

			            	var client = HttpClient.newHttpClient();

var request = HttpRequest.newBuilder()
            .uri(create("https://postman-echo.com/get/"))
            .build();

client.sendAsync(request, ofString())
      .thenApply(HttpResponse::body)
      .thenAccept(out::println)
      .join();				

For more, here is my tutorial @IBM Developer:
Java theory and practice: Explore the new Java SE 11 HTTP Client and WebSocket APIs.

WebSocket Client module

First implement the WebSocket.Listener interface:

			            	public final class EchoListener implements WebSocket.Listener {
    @Override
    public void onOpen(WebSocket webSocket) {
        logger.info("CONNECTED");
        ....
    }
    ....
}							

use an HttpClient to create a WebSocket

			            	WebSocket webSocket = httpClient.newWebSocketBuilder()
        .buildAsync(URI.create("ws://demos.kaazing.com/echo"),
                new EchoListener(executor)).join();

webSocket.sendClose(WebSocket.NORMAL_CLOSURE, "ok").thenRun(() -> logger.info("Sent close")).join();
			            

Old Switch statement

jshell> String getRomanNumber(int value){
    String romanValue = "";
    switch(value){
       case 0: romanValue = "nulla";
             break;
       case 1: romanValue = "I";
             break;
       case 2: romanValue = "II";
             break;
       case 3: romanValue = "III";
             break;
       case 4: romanValue = "IV";
             break;
       case 5: romanValue = "V";
             break;
       case 6: romanValue = "VI";
             break;
       case 7: romanValue = "VII";
             break;
       case 8: romanValue = "VIII";
             break;
       case 9: romanValue = "IX";
             break;
       case 10: romanValue = "X";
             break;
       default: System.out.printf("Out of range value: %d %n", value);
                romanValue = "N/A";
             break;
    }
   return romanValue;
}

New Switch statement - Java 12

mohamed_taman:~$ jshell --enable-preview
String getRomanNumber(int value){
    String romanValue = "";
    switch(value){
       case 0 -> romanValue = "nulla";
       case 1 -> romanValue = "I";
       case 2 -> romanValue = "II";
       case 3 -> romanValue = "III";
       case 4 -> romanValue = "IV";
       case 5 -> romanValue = "V";
       case 6 -> romanValue = "VI";
       case 7 -> romanValue = "VII";
       case 8 -> romanValue = "VIII";
       case 9 -> romanValue = "IX";
       case 10 -> romanValue = "X";
       default -> {
              System.out.printf("Out of range value: %d %n", value);
              romanValue = "N/A";
        }
    }
    return romanValue;
}

New Switch expression

String getRomanNumber(int value){
    return switch(value){
       case 0 -> "nulla";
       case 1 -> "I";
       case 2 -> "II";
       case 3 -> "III";
       case 4 -> "IV";
       case 5 -> "V";
       case 6 -> "VI";
       case 7 -> "VII";
       case 8 -> "VIII";
       case 9 -> "IX";
       case 10 -> "X";
       default -> throw new IllegalStateException("Out of range value: " + value);
    };
}

Multiple comma-separated labels in a single switch case

jshell> String getOddOrEvenNumber(int value){
    String kind = "N/A";
    switch(value){
       case 0: kind = "Zero"; break;
       case 1:
       case 3:
       case 5:
       case 7:
       case 9: kind = "Odd"; break;
       case 2:
       case 4:
       case 6:
       case 8:
       case 10: kind = "Even"; break;
       default: System.out.printf("Out of range: %d %n", value);
    }
   return kind;
}
jshell> var kind = switch(value){
   ...> case 0 -> "Zero";
   ...> case 1, 3, 5, 7, 9 -> "Odd";
   ...> case 2, 4, 6, 8, 10 -> "Even";
   ...> default -> throw new IllegalStateException("Out of range: " + value);
   ...> };

For more, here is my tutorial @IBM Developer:
Effective use of the new switch statement and expression in Java SE 12.

Yield and switch expression - Java 13

jshell>var value = 3
value ==> 3
jshell> String kind = switch(value){
   ...>  case 0: break "Zero";
   ...>  case 1, 3, 5, 7, 9: break "Odd";
   ...>  case 2, 4, 6, 8, 10: break "Even";
   ...>  default: throw new Exception("Out of range: " + value);};
kind ==> "Odd"

Dropping break & introducing yield

jshell> value = 10
value ==> 10
jshell> String kind = switch(value){
   ...>  case 0: yield "Zero";
   ...>  case 1, 3, 5, 7, 9: yield "Odd";
   ...>  case 2, 4, 6, 8, 10: yield "Even";
   ...>  default: throw new Exception("Out of range: " + value);};
kind ==> "Even"

This is why community feedback is important, & the preview feature is great for such changes.

- In Java 14 switch expressions is standardized.

New Text Blocks (Preview) - Java 13

History:

  • This feature intended to be introduced in Java 12 as Raw String Literals (Preview).
  • Re-introduced as Text Blocks (Preview) in Java 13.
  • Continue as Text Blocks (Second Preview) in Java 14.
  • And it is Text Blocks (Final) in Java 15.
var html = "\n" +
           "<html>\n" +
           "    <body>\n" +
           "        <p>Hello, world</p>\n" +
           "    </body>\n" +
           "</html>\n";
       
var html = """
            <html>
                <body>
                    <p>Hello, world</p>
                </body>
            </html>
            """;

Pattern Matching for instanceof (Preview) - Java 14, and (second preview) Java 15

JEP 305 JEP 375
//Old Days
if (obj instanceof String) {
   // Need to declare & cast again the object
   String str = (String) obj; 
   .. str.contains(..) ..
}else{
   .. str = ....
}
//Java 14 Onwards
if (obj instanceof String str) {
    // No need to declare str object again with casting
    .. str.contains(..) ..
} else {
    .. str....
}
//More complex examples
if (obj instanceof String str && str.length() > 5) { .. str.contains(..) .. }

The use of pattern matching in instanceof should dramatically reduce the overall number of explicit casts in Java programs.

Records (1st Preview) Java 14, (2nd Preview) Java 15, & (Standardized) Java 16

JEP 359 JEP 384 JEP 395
We need to write a lot of low-value, repetitive code to write a simple data carrier class responsibly: constructors, accessors, equals(), hashCode(), toString(), etc. To avoid this repetitive code, Java introduced records. In the Second preview it works well with Sealed Classes, and could be declared locally.
final class Point {
    public final int x;
    public final int y;

    public Point(int x, int y) {
        this.x = x;
        this.y = y;
    }
    // state-based implementations of equals, hashCode, toString
    // nothing else
record Point(int x, int y) { }

Helpful NullPointerExceptions - Java 14

JEP 358
Before Java 14, the JVM will print out the method, filename, and line number that caused the NPE:
a.i = 99;

Exception in thread "main" java.lang.NullPointerException
                        at Prog.main(Prog.java:5)
In Java 14 - Suppose an NPE occurs in this code:
a.b.c.i = 99;
Exception in thread "main" java.lang.NullPointerException:
    Cannot read field 'c' because 'a.b' is null.
at Prog.main(Prog.java:5)

Sealed Classes (Preview) - Java 15

JEP 360
It allow the author of a class or interface to control which code is responsible for implementing it. And it provide a more declarative way than access modifiers to restrict the use of a superclass.
package com.example.geometry;

public sealed class Shape
    permits Circle, Rectangle, Square {...}

public final class Circle extends Shape {...}

public sealed class Rectangle extends Shape 
    permits TransparentRectangle, FilledRectangle {...}

public final class TransparentRectangle extends Rectangle {...}

public final class FilledRectangle extends Rectangle {...}

public non-sealed class Square extends Shape {...}

Records (2nd Preview) - Java 15

JEP 359
It allow you to define a sealed interface and implement them on your records
sealed interface Car permits BMW, Audi { ... }

record BMW(int price) implements Car { ... }

record Audi(int price, String model) implements Car { ... }
Local records are a great boon for Java developers who would earlier have to create helper records
List<Merchant> findTopMerchants(List<Merchant> merchants, int month) {
    // Local record
    record MerchantSales(Merchant merchant, double sales) {}

    return merchants.stream()
        .map(merchant -> new MerchantSales(merchant, computeSales(merchant, month)))
        .sorted((m1, m2) -> Double.compare(m2.sales(), m1.sales()))
        .map(MerchantSales::merchant)
        .toList();
}

πŸ‘“

New language APIs

String class new enhancements

  • String repeat(int) - Java 11
    jshell> "no ".repeat(14).trim().concat(", Batman!")
    $1 ==> "no no no no no no no no no no no no no no, Batman!
  • boolean isBlank() - Java 11
    jshell>var blankText = "      "
    blankText ==> "      "
    
    jshell>blankText.trim().length() == 0
    $2 ==> true
    
    jshell>blankText.isBlank()
    $3 ==> true
  • String stripLeading() - Java 11
  • String stripTrailing() - Java 11
  • String strip() - Java 11
    jshell>var textWithSpaces = "\n \t      Text \u2005"
    textWithSpaces ==> "\n \t      Text  "
    
    jshell>textWithSpaces.trim()
    $4 ==> "Text  "
    
    jshell>textWithSpaces.strip()
    $5 ==> "Text"
  • Stream lines() - Java 11
    jshell> "\nOne\nTwo\nThree\nFour".lines().forEach(System.out::println)
    
    One
    Two
    Three
    Four
  • String indent(int) - Java 12
    jshell> "\nOne\nTwo\nThree\nFour".indent(5).indent(-2).lines().forEach(System.out::println)
    
    ... One
    ... Two
    ... Three
    ... Four
  • String transform(Function) - Java 12
    jshell> var text = "Text with*out *some* *asterisks"
    text ==> "Text wi*th *some* * asterisks"
    
    jshell> text.transform(String::toUpperCase)
       ...>     .transform(s -> s.replaceAll("\\*", ""))
       ...>     .transform(s -> s.split(" "))
    
    $1 ==> String[4] { "TEXT", "WITHOUT", "SOME", "ASTERISKS" }
    

For more, here is my tutorial @IBM Developer:
Java theory and practice: Explore new Java SE 11 and 12 APIs and language features.

As part of: Text Blocks (Preview) - Java 13

  • String formatted(Object[])
    jshell> "Hello %s!".formatted("World")
    |  Warning:
    |  formatted(java.lang.Object...) in java.lang.String has been deprecated and marked for removal
    |  "Hello %s!".formatted("World")
    |  ^-------------------^
    $11 ==> "Hello World!"
  • String stripIndent()
    jshell> var s1 = "    foo\n    bar" 
    s1 ==> "    foo\n    bar"
    jshell> System.out.println(s1); System.out.println(s1.stripIndent())
        foo
        bar
    foo
    bar
    |  Warning:
    |  stripIndent() in java.lang.String has been deprecated and marked for removal
    |   System.out.println(s1.stripIndent())
    |                      ^------------^

Text Blocks (Preview) methods continue - Java 13

  • String translateEscapes()
    jshell> System.out.println("\n".equals("\\n".translateEscapes()))
    true
    
    |  Warning:
    |  translateEscapes() in java.lang.String has been deprecated and marked for removal
    |  System.out.println("\n".equals("\\n".translateEscapes())); // true
    |                                 ^--------------------^
    

The curious ones out there will quickly spot that all the new methods are deprecated for removal

@Deprecated(forRemoval=true, since="13")

Compact number format with CompactNumberFormat - Java 12

Refers to the representation of a number in a short or human-readable form. For example, in the en_US locale, 1000 can be formatted as β€œ1K” and 1000000 as β€œ1M”.

For more, here is my tutorial @IBM Developer:
Java theory and practice: Explore new Java SE 11 and 12 APIs and language features.

Period-of-day was added to java.time - Java 16

Developers might want to express periods in a day, such as β€œin the morning," "in the afternoon," or β€œat night,”
not just a.m. or p.m.

For more, here is my article @Java Magazine:
Hidden gems in Java 16 and Java 17, from Stream.mapMulti to HexFormat.

Streams: The Teeing Collectors method - Java 12

Comparing 2 files - Java 12

what could we do with case such as this:

is πŸ“„ 1 == πŸ“„ 2 ??



It will compare all bytes and return -1 if match, otherwise will return the location of the first mismatching byte.

Re-implement the legacy Socket API - Java 13 - Java 19

  • Both the java.net.Socket and java.net.ServerSocket API implementations date back to JDK 1.0.

  • The implementation of these APIs uses several techniques (such as using the thread stack as the IO buffer) which make them inflexible and hard to maintain.

  • JDK 13 provides a new implementation, NioSocketImpl, which no longer requires native code, thus simplifying the act of porting to multiple platforms.

  • Make use of the existing buffer cache mechanism (eliminating the use of the thread stack for this purpose) and uses java.util.concurrent locks rather than synchronized methods.

  • This will make it simpler to integrate with Virtual Threads, which are being provided as part of Project Loom that is integrated with the JDK 19.

UTF-8 by default - Java 18

Write this on macOS or Linux

UTF-8 by default - Java 18

Read it on Windows OS

you will get this:

For more, here is my article @Java Magazine:
The not-so-hidden gems in Java 18: The JDK Enhancement Proposals.

πŸ›‘
Security &
Other Improvements

Improved container awareness

  • Since Java 10, Java is able to detect containers.
  • Query container instead of host OS.
  • Remote debugger, can attach to Java process.
  • For now works only for Linux & Docker on Linux.

To control the JVM:
-XX:ActiveProcessorCount=<n> , -XX:InitialRAMPercentage
-XX:MinRAMPercentage , -XX:MaxRAMPercentage

G1GC Garbage Collection 🧻 Improvements

Since Java 9 Garbage First Garbage Collector (G1GC) was made the default GC.

  • Incremental GC.
  • Parallel marking.
  • Designed for large heaps.
  • Tunable pause times.
  • It is slightly CPU intensive.
  • Java 9: Serial full GC.
  • Java 10: Parallel full GC.
    • -XX:ParallelGCThreads - to control number of CPU threads
  • Java 11: G1GC is more faster by 60%.
  • Java 12: Improving G1GC.
    • JEP 344: Abortable mixed collections for G1.
    • JEP 346: Promptly return unused committed memory from G1.

New Garbage Collectors

  • Java 11: Epsilon GC - Experimental
    • -XX:+UnlockExperimentalVMOptions
    • -XX:+UseEpsilonGC

  • Java 11: ZGC - Experimental
    • Keep pause time under 10ms.
    • No pause increase when heap increase.
    • Scale to multi-terabyte heaps.
    • -XX:+UnlockExperimentalVMOptions
    • -XX:+UseZGC

  • Java 14: ZGC on macOS - Experimental
    • Proposed under JEP 364.
    • Porting ZGC to macOS users.
  • Java 12: Shenandoah GC - Experimental
    • support of very large heaps.
    • low-pause time.

  • Java 13: ZGC: Uncommit unused memory - Experimental
    • Return pages that have been identified as unused for a sufficiently long period of time to the operating system.
    • Allows them to be reused for other processes.
    • Un-committing memory will never cause the heap size to shrink below the minimum size specified on the command line.
  • Java 15: two GCs are graduated to - Production
    • ZGC: A Scalable Low-Latency Garbage Collector.
    • Shenandoah: A Low-Pause-Time Garbage Collector.

Security Improvement: TLS 1.3 - Java 11, 15:

  • JEP 332 introduces support for the TLS 1.3.

  • As the JDK now supports this, although this does not extend to Datagram Transport Layer Security (DTLS).

  • Java 15 introduced - JEP 339: Edwards-Curve Digital Signature Algorithm (EdDSA), as described by RFC 8032.

Let's farewell some APIs goes bye bye...

New things come ... and sometimes old things have to go πŸ‘

Why I should know about them ?

Removed Methods

  • Java 11: Thread - destroy(), stop(Throwable)
  • Java 11: System, Runtime - runFinalizerOnExit()
  • Java 11: SecurityManager - checkAwtEventQueueAccess(), checkSystemClipboardAccess(), checkMemberAccess(), checkTopLevelWindow()
  • Java 12: FileInputStream, FileOutputStream - finalize(), stop(Throwable)
  • Java 12: com.sun.awt.SecurityWarning - is removed.

Removed Enterprise APIs - Java 11:

java.se.ee - related modules

The affected modules are:

  1. corba
  2. transaction
  3. activation
  4. xml.bind
  5. xml.ws
  6. xml.ws.annotation

Where is JavaFx has gone?

  • JavaFX is not part of JDK anymore & moved to OpenJFX since Java 11.
  • JavaFX maven dependency
    
      org.openjfx
      javafx-controls
      12.0.1
    
  • Run JavaFX -- For more Getting Started with JavaFX 12
    
      org.openjfx
      javafx-maven-plugin
      0.0.2
      
        HelloFX
      
    

Removed & Deprecated Technologies & tools

  • Java 10: policytool tool     - Removed
  • Java 10: javah tool           - Removed    - javac -h <dir>.
  • Java 10: -X:prof flag         - Removed     - jmap or VisualVM.
  • Java 11: Java Applet;        - Removed     - Java 8 is still supported.
  • Java 11: Java WebStart    - Removed     - jlink, jpackager tools.
  • Java 11: Nashorn engine   - Deprecated  - use Graal.js with GraalVM.
  • Java 14: Pack200 tools     - Removed     - use jlink or jpackage tools.
  • Java 15: Nashorn engine   - Removed    - use Graal.js with GraalVM.
  • Java 15: RMI Activation    - Deprecated   - for future removal.

Important Tools

Micro-benchmarking with JMH - Java 12

JMH: Java Micro-benchmarking Harness πŸ“Š


Micro-benchmarking is a performance-oriented practice that can steer implementation choices in code.

JMH allows you to write a simple Java class containing several methods that can be turned into a micro-benchmark using annotations. Many configuration options for the benchmark can also be configured through annotations.

JMH Example

import org.openjdk.jmh.annotations.Benchmark;
import org.openjdk.jmh.runner.*;
import org.openjdk.jmh.runner.options.*;

public class MyBenchmark {

  @Benchmark
  public void testMethod() {
     int a = 1;
     int b = 2;
     int sum = a + b;
  }

  public static void main(String[] args) throws RunnerException {
    Options opt = new OptionsBuilder()
            .include(MyBenchmark.class.getSimpleName())
            .forks(1)
            .build();

    new Runner(opt).run();
  }}						

For more visit official OpenJDK website:
OpenJDK JMH tool, and this is a good tutorial JMH - Java Microbenchmark Harness

All-in-One Java Troubleshooting Tool - Java 11


VisualVM is a visual tool integrating command line JDK tools and lightweight profiling capabilities. Designed for both development and production time use.

For more visit VisualVM official website:
https://visualvm.github.io/index.html

Flight Recorder ⏺ - Java 11

Flight Recorder is a low-overhead, data-collection framework for the JVM.

  • Prior to JDK 11, Flight Recorder was a commercial feature in the Oracle JDK binary.

  • Oracle is eliminates the functional differences between the Oracle JDK & one built from OpenJDK source code.

  • This feature open sourced to the OpenJDK throughJEP 328.

Simple Web Server - Java 18

  • Many development environments let programmers start up a rudimentary HTTP web server to test some functionality for static files. That capability comes to Java 18 through JEP 408.

  • The simplest way to start the web server is with the jwebserver command. By default, this command listens to localhost on port 8000. The server also provides a file browser to the current directory.
[mtaman]:~ jwebserver
Binding to loopback by default. For all interfaces use "-b 0.0.0.0" or "-b ::".
Serving /Users/mohamed_taman/Hidden Gems in Java 18/code and subdirectories on 127.0.0.1 port 8000
URL http://127.0.0.1:8000/

For more visit official my latest articles about JDK 18:
The not-so-hidden gems in Java 18: The JDK Enhancement Proposals,
and
The hidden gems in Java 18: The subtle changes

Presentation and Code
are hosted @My Github account.

Any Questions????