There were two more releases in-between:
As you can see, a lot of time passed, and there must be a lot of changes…
And there are!
(only major features and changes most relevant to developers follow)
The Java Linker (jlink tool) can be used to assemble and optimize a set of modules and their dependencies into a custom run-time (JEP 282)
var
"keyword"The var
"keyword" can be used in place of explicit type specialization for local
variables that have immediate initializer.
public String someMethod(int a, double b) {
var c = 2; // Automatically inferred as int
var compute = (a + c) * b; // Inferred as double
var result = new StringBuilder();
result.append("Your result is: ");
result.append(compute);
return result.toString();
}
Can also be used in for
-loops and try-with-resources statements
String
class changed from having a
char[]
field to byte[]
fieldExtension of the commercial CDS feature that Oracle's JVM has since Java 8.
It allows to reduce:
Scalable Low-Latency Garbage Collector (Experimental). Designed to meet the following goals:
Having file HelloWorld.java with the following content:
package hello;
public class World {
public static void main(String[] args) {
System.out.println("Hello World!");
}
}
You can run it using the java
application directly:
$ java HelloWorld.java
Hello World!
java.net.http
package
(JEP
321)final
variables in try-with-resourcesPreviously you had to declare new variable(s) for the purpose of using the resource it represents in the try-with-resources statement, for example:
public static Properties loadProperties(String filename) throws IOException {
try (var inputStream = new FileInputStream(new File(filename));
var reader = new InputStreamReader(inputStream, StandardCharsets.UTF_8)) {
final var properties = new Properties();
properties.load(reader);
return properties;
}
}
Now you can simply list the variables:
public static Properties loadProperties(String filename) throws IOException {
var inputStream = new FileInputStream(filename);
var reader = new InputStreamReader(inputStream, StandardCharsets.UTF_8);
try (inputStream; reader) {
final var properties = new Properties();
properties.load(reader);
return properties;
}
}
@SafeVargs
annotation on private
methods (previously it was only allowed on static
or
final
methods, or on constructors)
(JDK-7196160)private
methods in interfaces
(JDK-8071453)_
) is no longer allowed as a one-character identifier
(JDK-8061549)The new class VarHandle
residing in java.lang.invoke
provides
equivalents of java.util.concurrent.atomic
and sun.misc.Unsafe
operations upon object fields and array elements with similar performance.
The class java.util.concurrent.Flow
provides interfaces that support
the Reactive Streams publish-subscribe framework.
These interfaces support interoperability across a number of asynchronous systems running on JVMs.
New static factory methods on theList
, Set
, and Map
interfaces make it simpler to create immutable instances of those collections. For example:
final var numbersList = List.of("one", "two", "three");
final var numbersSet = Set.of("one", "two", "three");
final var numbersMap = Map.of("one", 1, "two", 2, "three", 3);
Can also create empty immutable lists / sets / maps:
final var emptyList = List.<String>of();
final var emptySet = Set.<String>of();
final var emptyMap = Map.<String, String>of();
List.copyOf()
, Set.copyOf()
and Map.copyOf()
methods create new immutable collection instances from existing instances.Collection
/ Map
is immutable, calling
copyOf()
will generally not create a copy.toUnmodifiableList()
, toUnmodifiableSet()
and toUnmodifiableMap()
added to the java.util.stream.Collectors
class. These allow the elements of a Stream
to be collected into
an unmodifiable collection.Optional.stream()
methodIf a value is present, returns a sequential Stream
containing only that value,
otherwise returns an empty Stream
.
This method can be used to transform a Stream
of optional elements
to a Stream
of present value elements:
Stream<Optional<T>> os = ...
Stream<T> s = os.flatMap(Optional::stream)
not()
predicate methodThe java.util.function.Predicate
interface has the new not()
method,
which negates the result of its supplied predicate (usage example will be
shown on the next slide)
String
classThe following methods were added: isBlank()
, lines()
,
strip()
, stripLeading()
, stripTrailing()
and repeat()
. Let's look at the example:
final var multilineString = "This is \n \u2003\r\n \u2002a Java 11\n\tMigration Guide";
multilineString.lines() // Stream of lines extracted from a String,
// separated by line terminators
.filter(not(String::isBlank)) // isBlank() returns true if string is empty
// or contains only white space codepoints
.map(String::strip) // akin to trim(),
// but accounts for white space in a Unicode sense
.forEach(System.out::println);
The above snippet outputs:
This is
a Java 11
Migration Guide
Files
classWith the inclusion of readString()
and writeString()
methods
and their overloads, it is easier to read and write text files:
final String fileAsText = Files.readString("readme.txt");
The following modules have been removed from the JDK 11:
java.xml.ws
(JAX-WS, plus the related technologies SAAJ
and Web Services Metadata)java.xml.bind
(JAXB)java.activation
(JAF)java.xml.ws.annotation
(Common Annotations)java.corba
(CORBA)java.transaction
(JTA)java.se.ee
(aggregator module for the 6 modules above)jdk.xml.ws
(tools for JAX-WS)jdk.xml.bind
(tools for JAXB)If you need the classes from these modules / packages in your applications, you'll need to explicitly include the external dependencies that implement them. Details later.
Download and install the build of Java 11 OpenJDK.
Here are sample flavors with corresponding links:
IntelliJ IDEA also supports automatic JDK download via its
Project Settings >
Platform Settings > SDKs configuration.
There are Docker images with JDKs pre-installed,
e.g. adoptopenjdk/openjdk11
Update all the things: your IDE, your build tool, its plugins,
and your project dependencies
(the latter addressed on the next slide to some extent).
Here are the recommended minimum versions for a few tools:
By this time (March 2021), even these versions are outdated,
so it is probably better to just upgrade to the latest available.
When project dependencies are concerned, one major thing that comes to mind is anything that operates on the bytecode, like:
Additionally, the dependencies that use the ones above, like:
Also, there are dependencies that cannot be upgraded,
because they do not receive support anymore, such as:
Since a lot of Java EE related modules were removed, you might be getting a compilation errors similar to the following one:
error: package javax.xml.bind does not exist
import javax.xml.bind.JAXBException;
^
It is also possible to get an exception at run-time:
Exception in thread "main" java.lang.NoClassDefFoundError: javax/xml/bind/JAXBException
at monitor.Main.main(Main.java:27)
Caused by: java.lang.ClassNotFoundException: javax.xml.bind.JAXBException
at java.base/jdk.internal.loader.BuiltinClassLoader.loadClass(BuiltinClassLoader.java:582)
at java.base/jdk.internal.loader.ClassLoaders$AppClassLoader.loadClass(ClassLoaders.java:185)
at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:496)
... 1 more
To resolve the "missing class" errors from the previous slide, add third-party dependencies (or use the reference ones) that contain the classes you need.
Here are Maven coordinates of some such dependencies (without versions):
com.sun.activation:javax.activation
javax.transaction:javax.transaction-api
com.sun.xml.bind:jaxb-impl
com.sun.xml.ws:jaxws-ri
javax.annotation:javax.annotation-api
See also this StackOverflow answer:
https://stackoverflow.com/a/48204154/2525313
To promote strong encapsulation, Module System of Java 9 allows
the library developers to mark certain parts of their code as "internal".
Consumers of such libraries won't be able to import classes
from such packages into their source code:
error: package com.sun.imageio.plugins.jpeg is not visible
import com.sun.imageio.plugins.jpeg.JPEG;
^
(package com.sun.imageio.plugins.jpeg is declared
in module java.desktop, which does not export it)
To allow for smoother transition from Java 8 to Java 11,
this limitation is relaxed to some extent for reflective access.
Instead of the "hard" error, JVM outputs a warning that looks like:
WARNING: An illegal reflective access operation has occurred
WARNING: Illegal reflective access by org.powermock.reflect.internal.WhiteboxImpl
(file: powermock-reflect-2.0.2.jar) to method java.lang.Object.clone()
WARNING: Please consider reporting this to the maintainers of org.powermock.reflect.internal.WhiteboxImpl
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
Most notably, the above warning can be seen when running tests
(if certain libraries, such as PowerMock are used).
To find out more about why this warning occurs and what it means, see
https://stackoverflow.com/questions/50251798/what-is-an-illegal-reflective-access
There are several approaches to turning the warning off:
You can open a package of a module for deep reflection by using
the --add-opens
command line option:
$ java \
--add-opens=java.base/java.lang=application-module \
-jar application.jar
The above command opens classes of package java.lang
of module
java.base
to all access from module application-module
.
If your code is not modularized, you can use special
module
name ALL-UNNAMED
, so the command above would become:
$ java \
--add-opens=java.base/java.lang=ALL-UNNAMED \
-jar application.jar
Since the warning appears on the stderr
,
you can simply redirect all such output to nowhere at the start of your program:
System.err.close();
System.setErr(System.out);
Another approach is to reset internal IllegalAccessLogger
with the help of Unsafe API.
public static void disableIllegalAccessWarning() {
try {
Field theUnsafe = Unsafe.class.getDeclaredField("theUnsafe");
theUnsafe.setAccessible(true);
Unsafe u = (Unsafe) theUnsafe.get(null);
Class cls = Class.forName("jdk.internal.module.IllegalAccessLogger");
Field logger = cls.getDeclaredField("logger");
u.putObjectVolatile(cls, u.staticFieldOffset(logger), null);
} catch (Exception ignored) {}
}
Some methods or even entire classes had been deprecated for quite some time, and then finally removed in Java 11. Here are some examples:
sun.misc.Base64
(but you can use java.util.Base64
instead)com.sun.java.swing.plaf.nimbus.NimbusLookAndFeel
(javax.swing.plaf.nimbus.NimbusLookAndFeel
can be used)It is still possible to compile for Java 1.6, 1.7, and 1.8 using the Java 11 JDK.
Be sure to specify the maven.compiler.release
property when using Maven.
For example, the following will target the Java 1.6 platform:
<maven.compiler.release>6</maven.compiler.release>
Gradle has similar settings (be sure to specify version as a string):
// In the root of build.gradle
sourceCompatibility = "1.8"
targetCompatibility = "1.8"
Stream
s
if you target 1.6 or 1.7)Scan the QR-code to get the GitHub repo link