Java 11 is around the corner and many people still use Java 8 in production. This example-driven tutorial covers the most important language and API features from Java 9 to 11. No walls of text, so let's dive right into the code. Enjoy!
Local Variable Type Inference
Java 10 has introduced a new language keyword
var which optionally replaces the type information when declaring local variables (local means variable declarations inside method bodies).
Prior to Java 10 you would declare variables like this:
Now you can replace
var. The compiler infers the correct type from the assignment of the variable. In this case
text is of type
Variables declared with
var are still statically typed. You cannot reassign incompatible types to such variables. This code snippet does not compile:
You can also use
final in conjunction with
var to forbid reassigning the variable with another value:
var is not allowed when the compiler is incapable of infering the correct type of the variable. All of the following code samples result in compiler errors:
Local variable type inference really shines with generics involved. In the next example
current has a rather verbose type of
Map<String, List<Integer>> which can be reduced to a single
var keyword, saving you from typing a lot of boilerplate:
As of Java 11 the
var keyword is also allowed for lambda parameters which enables you to add annotations to those parameters:
Tip: In Intellij IDEA you can hover on a variable while holding
CMD/CTRLto reveal the infered type of the variable (for keyboard junkies press
CTRL + J).
Java 9 introduced a new incubating
HttpClient API for dealing with HTTP requests. As of Java 11 this API is now final and available in the standard libraries package
java.net. Let's explore what we can do with this API.
HttpClient can be used either synchronously or asynchronously. A synchronous request blocks the current thread until the reponse is available.
BodyHandlers define the expected type of response body (e.g. as string, byte-array or file):
The same request can be performed asynchronously. Calling
sendAsync does not block the current thread and instead returns a
CompletableFuture to construct asynchronous operation pipelines.
We can omit the
.GET()call as it's the default request method.
The next example sends data to a given URL via
POST. Similiar to
BodyHandlers you use
BodyPublishers to define the type of data you want to send as body of the request such as strings, byte-arrays, files or input-streams:
The last sample demonstrates how to perform authorization via
Collections such as
Map have been extended with new methods.
List.of created a new immutable list from the given arguments.
List.copyOf creates an immutable copy of the list.
list is already immutable there's no practical need to actually create a copy of the list-instance, therefore
copy are the same instance. However if you copy a mutable list,
copy is indeed a new instance so it's garanteed there's no side-effects when mutating the original list:
When creating immutable maps you don't have to create map entries yourself but instead pass keys and values as alternating arguments:
Immutable collections in Java 11 still use the same interfaces from the old Collection API. However if you try to modify an immutable collection by adding or removing elements, a
java.lang.UnsupportedOperationExceptionis thrown. Luckily Intellij IDEA warns via an inspection if you try to mutate immutable collections.
Streams were introduced in Java 8 and now receive three new methods.
Stream.ofNullable constructs a stream from a single element:
takeWhile both accept a predicate to determine which elements to abandon from the stream:
If you're not yet familiar with Streams you should read my Java 8 Streams Tutorial.
Optionals also receive a few quite handy new methods, e.g. you can now simply turn optionals into streams or provide another optional as fallback for an empty optional:
One of the most basic classes
String gets a few helper methods for trimming or checking whitespace and for streaming the lines of a string:
Last but not least
InputStream finally gets a super useful method to transfer data to an
OutputStream, a usecase that's very common when working with streams of raw data.
Other JVM features
These are the - in my opinion - most interesting language new API features when moving from Java 8 to 11. But the feature list doesn't end here. There's a lot more packed into the latest Java releases:
- Flow API for reactive programming
- Java Module System
- Application Class Data Sharing
- Dynamic Class-File Constants
- Java REPL (JShell)
- Flight Recorder
- Unicode 10
- G1: Full Parallel Garbage Collector
- ZGC: Scalable Low-Latency Garbage Collector
- Epsilon: No-Op Garbage Collector
What's your favorite features? Let me know!
Where to go from here?
Many people (including me) are still using Java 8 in production. However as of the beginning of 2019 free support for JDK 8 ends. So this is a good time to migrate to Java 11 now. I wrote a migration guide how to move from Java 8 to 11 which hopefully helps you with your migration. You should also read my Java 8 and Stream API tutorials to learn more modern Java fundamentals. The source code of this tutorial is published on GitHub so feel free to play around with it (and leave a star if you like). You should also follow me on Twitter for more Java- and development-related stuff. Cheers!