Core Java

Java 11 New Features Tutorial

In this tutorial, I will talk about the JDK 11 product changes. Then I will dive into several API changes with Java examples. Finally I will show the new Single-File Launcher, which executes a Java source file without going through the compile processing.

1. Java 11 New Features – Introduction

Oracle JDK was free and richer than the OpenJDK prior to version 11 that was released on September 25, 2018. Oracle has shipped its OpenJDK at http://jdk.java.net/ and licensed it under GPL+CE since 2017. Oracle commercial JDK and OpenJDK are almost identical in version 11. Oracle commercial JDK is not free to use in production since version 11. Click here for more details about Oracle release cycle and the free-support expiration date.

There are other OpenJDK providers, such as IBM and RedHat. Click here for more details about OpenJDK providers comparison.

Java 11 includes lots of bug fixes and seventeen JDK Enhancement Proposals (JEPs). Here are the list of JEPs:

  • 181: Nest-Based Access Control
  • 309: Dynamic Class-File constants
  • 315: Improve Aarch6 Intrinsic
  • 318: Epsilon: A no-op Garbage collector (Experimental)
  • 320: Remove the Java EE and CORBA Modules
  • 321: HTTP Client (Standard)
  • 323: Local-Variable Syntax for Lambda Parameters
  • 324: Key Agreement with Curve25519 and Curve448
  • 327: Unicode 10
  • 328: Flight Recorder
  • 329: ChaCha20 and Poly1305 Cryptographic Algorithms
  • 330: Launch Single-File Source Code Programs
  • 331: Low-Overhead Heap Profiling
  • 332: Transport Layer Security (TLS) 1.3
  • 333: ZGC: A Scalable Low-Latency Garbage Collector (Experimental)
  • 336: Deprecate the Pack200 Tools and API

In this tutorial, I will use Oracle OpenJDK 11 to demonstrate the following API changes:

  • The java.lang.String class has six new methods.
  • The java.nio.file.Files class has four new static methods.
  • The java.util.function.Predicate has one new method.
  • The new java.net.http module supports httpclient.
  • Single file launcher executes the source code without compiling first.

2. Install Oracle OpenJDK 11

In this step, I will install Oracle OpenJDK 11 in my Windows 10 PC. Oracle outlines the installation steps here. Here are my steps:

Download http://jdk.java.net/11/. Extract the zip file into a folder. Mine is at C:\MaryZheng\DevTools\Java\OpenJDK11\jdk-11.0.2

Set up the environment variables for JAVA_HOME and PATH.

set environment variables

C:\MaryZheng\DevTools\Java>set JAVA_HOME=C:\MaryZheng\DevTools\Java\OpenJDK11\jdk-11.0.2

C:\MaryZheng\DevTools\Java>set PATH=%JAVA_HOME%\bin;%PATH%

C:\MaryZheng\DevTools\Java>where java
C:\MaryZheng\DevTools\Java\OpenJDK11\jdk-11.0.2\bin\java.exe

Verify that JDK11 is installed correctly by executing the command java -version

java -version

C:\MaryZheng\DevTools\Java>java -version
openjdk version "11.0.2" 2019-01-15
OpenJDK Runtime Environment 18.9 (build 11.0.2+9)
OpenJDK 64-Bit Server VM 18.9 (build 11.0.2+9, mixed mode)

3. Technologies Used

The example code in this article was built and run using:

  • Java 11
  • Maven 3.6.0
  • Eclipse
  • JUnit 4.12

I will create a simple Maven project. Pom.xml includes a Junit dependency.

pom.xml

<project xmlns="http://maven.apache.org/POM/4.0.0"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>
	<groupId>jdk11-demo</groupId>
	<artifactId>jdk11-demo</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<build>
		<sourceDirectory>src</sourceDirectory>
		<plugins>
			<plugin>
				<artifactId>maven-compiler-plugin</artifactId>
				<version>3.8.0</version>
				<configuration>
					<release>11</release>
				</configuration>
			</plugin>
		</plugins>
	</build>
	<dependencies>
		<dependency>
			<groupId>junit</groupId>
			<artifactId>junit</artifactId>
			<version>4.12</version>
		</dependency>
	</dependencies>
</project>

4. Changes at java.lang.String

JDK 11 enhances the java.lang.String class with six new methods:

  • boolean isBlank() – returns true if the string is empty or contains only white-spaces.
  • Stream <String> lines() – returns a stream of lines extracted from this string, separated by line terminators.
  • String repeat​(int count) – returns a string whose value is the concatenation of this string’s repeated count times.
  • String strip() – returns a string whose value is this string, with all leading and trailing white-spaces removed.
  • String stripLeading() – returns a string whose value is this string, with all leading white-spaces removed.
  • String stripTrailing() – returns a string whose value is this string, with all trailing white-spaces removed.

In this step, I will create a StringTest.java class to demonstrate these new methods. Click here for a very detailed example.

StringTest.java

package org.jcg.zheng;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;

import java.util.List;
import java.util.stream.Collectors;

import org.junit.Test;

public class StringTest {

    private static final char UNICODE_SPACE_VER52 = '\u2000';
    private static final char ASCII_UTF8 = '\u0020';

    @Test
    public void test_repeat() {
        String test = new String("Test");
        String longString = test.repeat(10);
        assertEquals("TestTestTestTestTestTestTestTestTestTest", longString);
    }

    @Test
    public void test_lines() {
        String multipleLinesString = "First line.\nSecond line.\nThird line.\n";
        List<String> lines = multipleLinesString.lines().collect(Collectors.toList());

        assertEquals("First line.", lines.get(0));
        assertEquals("Second line.", lines.get(1));
        assertEquals("Third line.", lines.get(2));
    }

    @Test
    public void test_stripLeading() {
        String hasLeadingWhiteSpace = " Test  ";
        String clearedTest = hasLeadingWhiteSpace.stripLeading();
        assertEquals("Test  ", clearedTest);
    }

    @Test
    public void test_stripTrailing() {
        String hasLeadingWhiteSpace = " Test  ";
        String clearedTest = hasLeadingWhiteSpace.stripTrailing();
        assertEquals(" Test", clearedTest);
    }

    @Test
    public void test_strip() {
        String hasLeadingWhiteSpace = " Test\t\n  ";
        String clearedTest = hasLeadingWhiteSpace.strip();
        assertEquals("Test", clearedTest);
    }

    @Test
    public void test_trim() {
        String hasLeadingWhiteSpace = " Test\t\n  ";
        String clearedTest = hasLeadingWhiteSpace.trim();
        assertEquals("Test", clearedTest);
    }

    @Test
    public void trim_vs_strip() {
        String testStr = UNICODE_SPACE_VER52 + "abc" + UNICODE_SPACE_VER52;

        assertTrue(Character.isWhitespace(UNICODE_SPACE_VER52));
        assertEquals(UNICODE_SPACE_VER52 + "abc" + UNICODE_SPACE_VER52, testStr.trim());

        // Strip is Unicode-aware
        assertEquals("abc", testStr.strip());

        testStr = ASCII_UTF8 + "abc" + ASCII_UTF8;
        assertTrue(Character.isWhitespace(ASCII_UTF8));
        assertEquals("abc", testStr.trim());
        assertEquals("abc", testStr.strip());

        testStr = '\u001F' + "abc" + '\u001F';
        assertTrue(Character.isWhitespace('\u001F'));
        assertEquals("abc", testStr.trim());
        assertEquals("abc", testStr.strip());

    }

    @Test
    public void test_isBlank() {
        assertTrue("".isBlank());
        assertTrue(System.getProperty("line.separator").isBlank());
        assertTrue("\t".isBlank());
        assertTrue("    ".isBlank());
        assertTrue("\t\n    ".isBlank());
    }
}

Note: The existing trim() method provides the same functions as the strip() method with the only difference being the white-space definition. In the trim() method, the white-space is defined as any character whose codepoint is less than or equal to \u0020. In the strip() method, the white-space is defined by the static Character.isWhitespace method.

5. Changes at java.nio.file.Files

Java 11 enhances java.nio.file.Files by adding four new static methods to read string from a file and write string into a file directly:

  • static String readString(Path path) – reads contents from a file into a string, decoding from bytes to characters using the UTF-8 charset.
  • static String readString(Path path, Charset cs) – reads characters from a file into a string, decoding from bytes to characters using the specified charset.
  • static Path writeString(Path path, CharSequence csq, OpenOption… options) – writes a CharSequence to a file
  • static Path writeString(Path path, CharSequence csq, Charset cs, OpenOption… options) – writes a CharSequence to a file with the specified charset.

In this step, I will create a FilesTest.java to show you how to use these methods to read string from a file and write string to a file.

FilesTest.java

package org.jcg.zheng;

import static org.junit.Assert.assertEquals;

import java.io.IOException;
import java.nio.charset.Charset;
import java.nio.file.Files;
import java.nio.file.Path;

import org.junit.Test;

public class FilesTest {

    @Test
    public void writeString_readString() {
        try {
            Path localFile = Path.of("C:\\MaryZheng\\Temp\\test.txt");
            String sampleString = "Some example of text";
            Files.writeString(localFile, sampleString);

            String readData = Files.readString(localFile);
            assertEquals(sampleString, readData);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    @Test
    public void writeString_readString_utf8() {
        try {
            String sampleString = "Some example of text";
            Files.writeString(Path.of("test.txt"), sampleString, Charset.forName("UTF-8"));

            String readData = Files.readString(Path.of("test.txt"));
            assertEquals(sampleString, readData);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

}

6. Change at java.util.Predicate

JDK11 enhances java.util.function.Predicate with a static not() method.

static <T> Predicate<T> not​(Predicate<? super T> target) – returns a predicate that is the negation of the supplied predicate.

In this step, I will create a PredicateTest.java to show how to use the not method to filter out an empty name from a list of names.

PredicateTest.java

package org.jcg.zheng;

import static org.junit.Assert.assertEquals;

import java.util.List;
import java.util.function.Predicate;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import org.junit.Test;

public class PredicateTest {

    @Test
    public void test_Predicate_Not() {

        String[] names = { "TEST", "MARY", " ", "" };

        List loweCaseList = Stream.of(names).filter(Predicate.not(String::isBlank))
                .collect(Collectors.toList());
        assertEquals(2, loweCaseList.size());
    }

}

7. New HttpClient Module

JDK 11 provides a new module – java.net.http. It supports both HTTP/1.1 and HTTP/2 and replaces the legacy HttpUrlConnection class. It includes several new classes:

  • HttpClient – sends requests and receive responses. It uses a builder to create an instance.
  • HttpRequest – encapsulates an HTTP request. A request is constructed using a builder. HttpRequest.BodyPublisher handles when a request has a body.
  • HttpResponse – encapsulates an HTTP response. HttpResponse.BodyHandler handles the response body.

In this step, I will create an HttpClientTest.java to show how to invoke Restful services to create, read, update, and delete a user.

HttpClientTest.java

package org.jcg.zheng;

import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpRequest.BodyPublishers;
import java.net.http.HttpResponse;
import java.net.http.HttpResponse.BodyHandlers;

import org.junit.Before;
import org.junit.Test;

public class HttpClientTest {

    private HttpClient client;
    String serviceUri;

    @Before
    public void setup() {
        client = HttpClient.newHttpClient();// default to HTTP_2
        serviceUri = "https://reqres.in/api/users";
    }

    @Test
    public void get_ofString() {
        String getUrl = serviceUri + "/2";
        HttpRequest request = HttpRequest.newBuilder().uri(URI.create(getUrl)).build();
        HttpResponse response;
        try {
            response = client.send(request, BodyHandlers.ofString());
            System.out.println("Response" + response.body());
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    @Test
    public void put_ofString() {
        String putUrl = serviceUri + "/2";
        String upUsdateerString = "{\"name\": \"Mary\",  \"job\": \"leader\"}";
        HttpRequest request = HttpRequest.newBuilder().uri(URI.create(putUrl))
                .PUT(BodyPublishers.ofString(upUsdateerString)).build();
        HttpResponse response;
        try {
            response = client.send(request, BodyHandlers.ofString());
            System.out.println("Response" + response.body());
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    @Test
    public void post_discarding() {
        String newUserString = "{\"name\": \"Mary\",  \"job\": \"leader\"}";
        HttpRequest request = HttpRequest.newBuilder().uri(URI.create(serviceUri))
                .POST(BodyPublishers.ofString(newUserString)).build();
        try {
            HttpResponse response = client.send(request, BodyHandlers.discarding());
            System.out.println("Response" + response.statusCode());
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    @Test
    public void delete_ofString() {
        String deleteUrl = serviceUri + "/2";
        HttpRequest request = HttpRequest.newBuilder().uri(URI.create(deleteUrl)).DELETE().build();
        try {
            HttpResponse response = client.send(request, BodyHandlers.discarding());
            System.out.println("Response" + response.statusCode());
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

}

8. New Single-File Launcher

JDK11’s new single-file launcher allows executing Java source codes directly using the java interpreter. The source code is compiled in memory and then executed by the interpreter. The limitation is that all the classes have to be defined in the same file.

In this step, I will create a java source file which has a public static main method and prints out a “hello world” message.

8.1 A Source File

SingleFileLauncher .java

public class SingleFileLauncher {
    public static void main(String[] args) {
        System.out.println("Hello World!!!");
    }
}

8.2 Demo with javac and java

Prior to Java 11, you need to do two steps:

  • Run javac.exe to generate the byte-code class files
  • Execute java with a class name.

javac command example

C:\MaryZheng\Workspaces\jdk11-demo\src\main\java>javac SingleFileLauncher.java

C:\MaryZheng\Workspaces\jdk11-demo\src\main\java>dir
 Volume in drive C is OSDisk
 Volume Serial Number is 528C-6C8F

 Directory of C:\MaryZheng\Workspaces\jdk11-demo\src\main\java

03/10/2019  01:04 PM    <DIR>          .
03/10/2019  01:04 PM    <DIR>          ..
02/18/2019  01:52 PM    <DIR>          org
03/10/2019  01:04 PM               444 SingleFileLauncher.class
03/10/2019  12:44 PM               138 SingleFileLauncher.java
               2 File(s)            582 bytes
               3 Dir(s)  25,755,234,304 bytes free

C:\MaryZheng\Workspaces\jdk11-demo\src\main\java>

java command example

C:\MaryZheng\Workspaces\jdk11-demo\src\main\java>java SingleFileLauncher
Hello World!!!

C:\MaryZheng\Workspaces\jdk11-demo\src\main\java>

8.3 Demo with Single-File Launcher

In Java 11, you can run java with a java source file name directly.

java ${fileName.java}

C:\MaryZheng\Workspaces\jdk11-demo>java src\main\java\SingleFileLauncher.java
Hello World!!!

C:\MaryZheng\Workspaces\jdk11-demo>

Note: The java source file name follows the file format not the java package format.

9. Summary

In this tutorial, I demonstrated five API changes in Java 11:

  • The java.lang.String class – six new methods
  • The java.nio.file.Files class – four new static methods
  • The java.util.function.Predicate – one new method
  • The new java.net.http module – httpclient
  • Single file launcher – execute source code without compiling first

But there are more changes in Java 11 than the ones demonstrated here. Please visit Oracle web site for more details.

10. Download the Source Code

This was a Java 11 new features tutorial.

Download
You can download the full source code of this example here: Java 11 New Features Tutorial

Mary Zheng

Mary has graduated from Mechanical Engineering department at ShangHai JiaoTong University. She also holds a Master degree in Computer Science from Webster University. During her studies she has been involved with a large number of projects ranging from programming and software engineering. She works as a senior Software Engineer in the telecommunications sector where she acts as a leader and works with others to design, implement, and monitor the software solution.
Subscribe
Notify of
guest

This site uses Akismet to reduce spam. Learn how your comment data is processed.

1 Comment
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
Warren Goldman
Warren Goldman
2 years ago

Though the last test passes, it actually throws an exception, which is caught and gobbled in the catch (the stacktrace is printed, see below)

java.io.IOException: unexpected content length header with 204 response
at java.net.http/jdk.internal.net.http.HttpClientImpl.send(HttpClientImpl.java:565)
at java.net.http/jdk.internal.net.http.HttpClientFacade.send(HttpClientFacade.java:119)
at ….HttpClientTest.delete_ofString(HttpClientTest.java:75)

Back to top button