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.
Table Of Contents
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 supportshttpclient
. - 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 theUTF-8 charset
.static String readString(Path path, Charset cs)
– reads characters from a file into a string, decoding from bytes to characters using the specifiedcharset
.static Path writeString(Path path, CharSequence csq, OpenOption… options)
– writes aCharSequence
to a filestatic Path writeString(Path path, CharSequence csq, Charset cs, OpenOption… options)
– writes aCharSequence
to a file with the specifiedcharset
.
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.
You can download the full source code of this example here: Java 11 New Features Tutorial
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)