What is new in Java 18
Java 18 reached general availability on 22 March 2022, download Java 18 here.
Java 18 has 9 JEP items.
- 1. JEP 400: UTF-8 by Default
- 2. JEP 408: Simple Web Server
- 3. JEP 413: Code Snippets in Java API Documentation
- 4. JEP 416: Reimplement Core Reflection with Method Handles
- 5. JEP 417: Vector API (Third Incubator)
- 6. JEP 418: Internet-Address Resolution SPI
- 7. JEP 419: Foreign Function & Memory API (Second Incubator)
- 8. JEP 420: Pattern Matching for switch (Second Preview)
- 9. JEP 421: Deprecate Finalization for Removal
- Download Source Code
- References
Java 18 developer features.
No new developer features, mainly preview and incubator, Pattern Matching for switch (second preview), Vector API (Third Incubator) and Foreign Function & Memory API (Second Incubator).
1. JEP 400: UTF-8 by Default
In Java 18, this JEP makes the default charset to UTF-8. However, we still allow configuring the default charset to others by providing the system property ‘file.encoding’.
In Java 18, if the file.encoding
system property is COMPACT
, the JVM uses Java 17 and an earlier algorithm to choose the default charset.
java -Dfile.encoding=COMPAT
If the file.encoding
is UTF-8, the default charset will be UTF-8, a no-op value in Java 18.
java -Dfile.encoding=UTF-8
Long story short
Before Java 18, the default charset was environment-dependent, meaning the Java Virtual Machine (JVM) chooses the default charset during start-up, based on the run-time environment, like the operating system, the user’s locale, and other factors. For example, on macOS, the default charset is UTF-8; on Windows, the default charset is ‘windows-1252’ (if English locale).
Since the default charset is not the same from machine to machine, APIs that use the default charset may cause unwanted behaviors or errors, especially the IO APIs like java.io.FileReader
and java.io.FileWriter
.
Further Reading
2. JEP 408: Simple Web Server
This JEP provides a command-line tool, jwebserver
to start a simple web server to serve static files, suitable for prototyping, ad-hoc coding, testing, and educational purpose, not for a production server.
By default, the jwebserver
starts a simple web server at port 8000
, and serves the static files from the current directory that start the command. Furthermore, it serves only HEAD and GET requests, and other requests will receive a 501 – Not Implemented or a 405 – Not Allowed response.
./jwebserver
Binding to loopback by default. For all interfaces use "-b 0.0.0.0" or "-b ::".
Serving /Library/Java/JavaVirtualMachines/temurin-18.jdk/Contents/Home/bin and subdirectories on 127.0.0.1 port 8000
URL http://127.0.0.1:8000/
127.0.0.1 - - [10/Nov/2022:18:59:22 +0800] "GET / HTTP/1.1" 200 -
Access http://127.0.0.1:8000
The below command starts a static web server at port 8888
.
# We can use `-p` option to start the web server at different port
./jwebserver -p 8888
The below command starts a static web server at port 8888 and serves files from the directory /Users/mkyong
.
# We can use `-d` option to serve static files from a specified directory
./jwebserver -p 8888 -d /Users/mkyong
Further Reading
3. JEP 413: Code Snippets in Java API Documentation
Before Java 18, we used {@code ...}
to include the source code snippets in the documentation like this:
/**
* <pre>{@code
* int sum = widgets.stream()
* .filter(w -> w.getColor() == RED)
* .mapToInt(w -> w.getWeight())
* .sum();
* }</pre>
*/
The javadoc
tool will render the body of the {@code ...}
tag as HTML code. This method has some disadvantages, like the inability to do syntax highlighting, can’t to contain HTML markups, indentation issues, etc.
This JEP introduces the @snippet
tag to allow developers to be more flexible in including source code snippets in the documentation.
Inline snippets
The generated documentation will render the body of the {@snippet ...}
tag as HTML code. There is no need to escape special characters like < and
>` with HTML entities.
/**
* The following code shows how to use {@code Optional.isPresent}:
* {@snippet :
* if (v.isPresent()) {
* System.out.println("v: " + v.get());
* }
* }
*/
External snippets
This includes the source code snippet from a separate file.
A comment from ShowExample.java
links the source code snippets from a separate file ShowOptional.java
.
public class ShowExample {
/**
* The following code shows how to use {@code Optional.isPresent}:
* {@snippet file="ShowOptional.java" region="example"}
*/
void test() {
//...
}
}
Where ShowOptional.java
is a file containing:
public class ShowOptional {
void show(Optional<String> v) {
// @start region="example"
if (v.isPresent()) {
System.out.println("v: " + v.get());
}
// @end
}
}
The content of the requested @start
and @end
regions will include in the ShowExample.java
documentation.
if (v.isPresent()) {
System.out.println("v: " + v.get());
}
Further Reading
Refer to the official JEP 413 for more @snippet
examples like syntax highlighting, replacing the string, etc.
4. JEP 416: Reimplement Core Reflection with Method Handles
The existing core reflection has three internal mechanisms for invoking methods and constructors. Adding new features to the core reflection may modify all three code paths. Which is costly.
- VM native methods
- Dynamically generated bytecode stubs
- Method handles
This JEP reimplements core reflection with method handles as the underlying reflective mechanism. There is no change to the java.lang.reflect
API; solely an implementation change.
P.S We can enable back the old implementation via -Djdk.reflect.useDirectMethodHandle=false
.
Further Reading
5. JEP 417: Vector API (Third Incubator)
This JEP improves the Vector API performance and other enhancements in response to feedback.
History
- Java 16, JEP 338 introduced new Vector API as an incubating API.
- Java 17, JEP 414 enhanced the Vector API second incubator.
Further Reading
6. JEP 418: Internet-Address Resolution SPI
By default, the java.net.InetAddress
API uses the operating system’s built-in resolver to resolve host names to Internet Protocol (IP) addresses.
InetAddress ip = InetAddress.getByName("google.com");
This JEP redesign java.net.InetAddress
API to use service loader to find the resolver instead of using the operating system’s built-in resolver.
private static InetAddressResolver loadResolver() {
return ServiceLoader.load(InetAddressResolverProvider.class)
.findFirst()
.map(nsp -> nsp.get(builtinConfiguration()))
.orElse(BUILTIN_RESOLVER);
}
Further Reading
7. JEP 419: Foreign Function & Memory API (Second Incubator)
This Foreign Function & Memory API allows the developer to access the code outside the JVM (foreign functions), data stored outside the JVM (off-heap data), and accessing memory not managed by the JVM (foreign memory).
This JEP improves the Foreign Function & Memory API and other enhancements in response to feedback.
History
- Java 14 JEP 370 introduced Foreign-Memory Access API (Incubator).
- Java 15 JEP 383 introduced Foreign-Memory Access API (Second Incubator).
- Java 16 JEP 389 introduced Foreign Linker API (Incubator).
- Java 16 JEP 393 introduced Foreign-Memory Access API (Third Incubator).
- Java 17 JEP 412 introduced Foreign Function & Memory API (Incubator).
- Java 18 JEP 419 introduced Foreign Function & Memory API (Second Incubator).
P.S Please refer to previous Foreign Linker API examples in Java 16.
Further Reading
8. JEP 420: Pattern Matching for switch (Second Preview)
This JEP is the second preview of pattern matching for the switch, with the following enhancements since the first preview:
8.1. Dominance checking of the same type.
Review the below switch
pattern matching, every value that matches the String s
also matches the CharSequence cs
, which makes String s
unreadable and will cause a compile-time error.
static void error (Object o){
switch (o) {
case CharSequence cs -> System.out.println("A sequence of length " + cs.length());
case String s -> // Error - pattern is dominated by previous pattern
System.out.println("A string: " + s);
default -> {
break;
}
}
}
If we run the above code with Java 18, it will cause a compile-time error.
java: this case label is dominated by a preceding case label
The IntelliJ IDE will highlight the error label and show a more user-friendly error message when you hover over it.
Label is dominated by a preceding case label 'CharSequence cs'
8.2 Exhaustiveness of switch expressions and statements
The switch expression requires all possible values to be handled in the switch block, else prompts a compile-time error.
Review the below code:
static int coverage(Object o) {
return switch (o) { // Error - not exhaustive
case String s -> s.length();
case Integer i -> i;
};
}
If we run the above code with Java 18, it will cause a compile-time error.
java: the switch expression does not cover all possible input values
The below code is fine because the default
will handle all the possible types.
static int coverage(Object o) {
return switch (o) {
case String s -> s.length();
case Integer i -> i;
default -> 0;
};
}
History
- Java 17 JEP 406 introduced Pattern Matching for switch (Preview).
- Java 18 JEP 420 introduced Pattern Matching for switch (Second Preview).
P.S Please refer to the previous Pattern Matching for switch examples in Java 17.
Further Reading
9. JEP 421: Deprecate Finalization for Removal
The object finalization is unpredictable and dangerous; read this and this.
// deprecated since Java 9
@Deprecated(since="9", forRemoval=true)
protected void finalize() throws Throwable { }
This JEP deprecates (again?) finalization for removal in the future release. In Java 18, we can use the command-line option --finalization=disabled
to disable finalization. The finalization remains enabled by default;
Review the below try-finally code; if the copy throws an exception, or the output.close();
throws an exception, then the input will never close and cause the resource to leak.
package com.mkyong.java18.jep421;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
public class JEP421 {
public static void main(String[] args) throws IOException {
String file1 = "/Home/mkyong/file1";
String file2 = "/Home/mkyong/file1";
FileInputStream input = null;
FileOutputStream output = null;
try {
input = new FileInputStream(file1);
output = new FileOutputStream(file2);
// copy files from file1 to file 2
output.close();
output = null;
input.close();
input = null;
} finally {
if (output != null) output.close();
if (input != null) input.close();
}
}
}
The better solution is to use Java 7 try-with-resources to properly open and close the resources.
try (FileInputStream input = new FileInputStream(file1);
FileOutputStream output = new FileOutputStream(file2)) {
// copy files from file1 to file 2
}
Further Reading
Download Source Code
$ git clone https://github.com/mkyong/core-java
$ cd java-18