90 New Features and APIs in JDK 11 (Part 1)
Are you excited to learn more about the features available in JDK 11? Check out this installment looking at the new developer visible features.
Join the DZone community and get the full member experience.
Join For FreeThe new six-month release cadence of the JDK means that before we’ve even really figured out what the new features are in JDK 10 along comes JDK 11. I posted an earlier blog where I listed all 109 new features and APIs I could find in JDK 10, so it seemed obvious to do the same thing for JDK 11. I’m going to use a different format from the previous post. In this post, I’ll divide everything into two sections: features that are visible to developers and everything else. This way, if you’re interested in just what will affect your development work, you can check out the second installment.
The total I counted was 90 (that’s JEPs plus new classes and methods, excluding the individual ones for the HTTP client and Flight Recorder). Although that’s eleven less than I found in JDK 10, I think it’s fair to say more functionality has been added to JDK 11 — certainly at the JVM level.
Developer Visible Features
JDK 11 is pretty light on things that change the way you code. There is one small change to the language syntax, a fair number of new APIs, and the ability to run single-file applications without the need to use the compiler. Also, the removal of the java.se.ee aggregator module is now visible, which may impact migrating an existing application to JDK 11.
JEP 323: Local-Variable Syntax for Lambda Parameters
JDK 10 introduced the Local-Variable Type Inference (JEP 286). This simplifies the code, as you no longer need to explicitly state the type of a local-variable but can, instead, use var
. JEP 323 extends the use of this syntax to the parameters of Lambda expressions. Here’s a simple example:
list.stream()
.map((var s) -> s.toLowerCase())
.collect(Collectors.toList());
Of course, the astute Java programmer would point out that Lambda expressions already have type inference so the use of var
would (in this case) be superfluous. We could just as easily write the same code as:
list.stream()
.map(s -> s.toLowerCase())
.collect(Collectors.toList());
Why add var
support, then? The answer is for one special case, which is when you want to add an annotation to the Lambda parameter. It is not possible to do this without a type being involved. To avoid having to use the explicit type, we can use var
to simplify things, thus:
list.stream()
.map((@Notnull var s) -> s.toLowerCase())
.collect(Collectors.toList());
This feature has required changes to the Java Language Specification (JLS), specifically:
- Page 24: The description of the
var
special identifier. - Page 627-30: Lambda parameters.
- Page 636: Runtime evaluation of Lambda expressions.
- Page 746: Lambda syntax.
JEP 330: Launch Single-File Source-Code Programs
One of the criticisms of Java is that it can be verbose in its syntax and the ‘ceremony’ associated with running even a trivial application can make it hard to approach as a beginner. To write an application that just prints “Hello World!,” it requires you to write a class with a public static void main
method and use the System.out.println
method. Having done this, you must then compile the code using javac. Finally, you can run the application to be welcomed into the world. Doing the same thing in most scripting languages is significantly simpler and quicker.
JEP 330 eliminates the need to compile a single-file application, so now you can type:
java HelloWorld.java
The Java launcher will identify that the file contains Java source code and will compile the code to a class file before executing it.
Parameters placed after the name of the source file are passed as parameters when executing the application. Parameters placed before the name of the source file are passed as parameters to the Java launcher after the code has been compiled. This allows for things like the classpath to be set on the command line. Parameters that are relevant to the compiler (such as the classpath) will also be passed to javac for compilation.
As an example:
java -classpath /home/foo/java Hello.java Bonjour
would be equivalent to:
javac -classpath /home/foo/java Hello.java
java -classpath /home/foo/java Hello Bonjour
This JEP also provides ‘shebang’ support. To reduce the need to even mention the Java launcher on the command line, this can be included on the first line of the source file. For example:
#!/usr/bin/java --source 11
public class HelloWorld {
...
It is necessary to specify the –source
flag with the version of Java to use.
JEP 321: HTTP Client (Standard)
JDK 9 introduced a new API to provide support for the HTTP Client protocol (JEP 110). Since JDK 9 introduced the Java Platform Module System (JPMS), this API was included as an incubator module. Incubator modules are intended to provide new APIs without making them part of the Java SE standard. Developers can try the API and provide feedback. Once any necessary changes have been made (this API was updated in JDK 10), the API can be moved to become part of the standard.
The HTTP Client API is now part of the Java SE 11 standard. This introduces a new module and package to the JDK, java.net.http. The main types defined are:
- HttpClient
- HttpRequest
- HttpResponse
- WebSocket
The API can be used synchronously or asynchronously. The asynchronous mode makes use of CompletableFutures
and CompletionStages
.
JEP 320: Remove The Java EE and CORBA Modules
With the introduction of JPMS in JDK 9, it was possible to divide the monolithic rt.jar file into multiple modules. An additional advantage of JPMS is it is now possible to create a Java runtime that only includes the modules you need for your application, reducing the size considerably. With cleanly defined module boundaries, it is now simpler to remove parts of the Java API that are outdated. This is what this JEP does; the java.se.ee meta-module includes six modules that will no longer be part of the Java SE 11 standard and not included in the JDK. The affected modules are:
- corba
- transaction
- activation
- xml.bind
- xml.ws
- xml.ws.annotation
These modules have been deprecated since JDK 9 and were not included by default in either compilation or runtime. If you had tried compiling or running an application that used APIs from these modules on JDK 9 or JDK 10, they would have failed. If you use APIs from these modules in your code, you will need to supply them as a separate module or library. From asking audiences at my presentations, it seems that the java.xml modules, which are part of the JAX-WS, SOAP-based web services support are the ones that will cause most problems.
New APIs
A lot of the new APIs in JDK 11 result from the HTTP client module now being part of the standard, as well as the inclusion of Flight Recorder.
For a complete list of API changes, I refer the reader to the excellent comparison of different JDK versions produced by Gunnar Morling, which is available on Github.
What I list here are all the new methods other than those in the java.net.http and jdk.jfr modules. I’ve also not listed the new methods and classes in the java.security modules, which are pretty specific to the changes of JEP 324 and JEP 329 (there are six new classes and eight new methods).
java.io.ByteArrayOutputStream
- void writeBytes(byte[]): Write all the bytes of the parameter to the output stream
java.io.FileReader
Two new constructors that allow a Charset to be specified.
java.io.FileWriter
Four new constructors that allow a Charset to be specified.
java.io.InputStream
-
io.InputStream nullInputStream()
: Returns anInputStream
that reads no bytes. When you first look at this method (and the ones inOutputStream
,Reader
, andWriter
), you wonder what use they are. You can think of them like /dev/null for throwing away an output you don’t need or providing an input that always returns zero bytes.
java.io.OutputStream
-
io.OutputStream nullOutputStream()
java.io.Reader
-
io.Reader nullReader()
java.io.Writer
-
io.Writer nullWriter()
java.lang.Character
-
String toString(int)
: This is an overloaded form of the existing method but takes an int instead of a char. The int is a Unicode code point.
java.lang.CharSequence
- int compare(
CharSequence
,CharSequence
): Compares twoCharSequence
instances lexicographically. Returns a negative value, zero, or a positive value if the first sequence is lexicographically less than, equal to, or greater than the second, respectively.
java.lang.ref.Reference
-
lang.Object clone()
: I must admit, this one confuses me. TheReference
class does not implement theCloneable
interface and this method will always throw aCloneNotSupportedException
. There must be a reason for its inclusion, presumably for something in the future.
java.lang.Runtime
java.lang.System
No new methods here but worth mentioning that the runFinalizersOnExit()
method has now been removed from both these classes (this could be a compatibility issue).
java.lang.String
I think this is one of the highlights of the new APIs in JDK 11. There are several useful new methods here.
-
boolean isBlank()
: Returns true if the string is empty or contains only white space codepoints, otherwise false. -
Stream lines()
: Returns a stream of lines extracted from this string, separated by line terminators. -
String repeat(int)
: Returns a string whose value is the concatenation of this string repeated count times. -
String strip()
: Returns a string whose value is this string, with all leading and trailing whitespace removed. -
String stripLeading()
: Returns a string whose value is this string, with all leading whitespace removed. -
String stripTrainling()
: Returns a string whose value is this string, with all trailing whitespace removed.
You probably look at strip()
and ask, “How is this different to the existing trim()
method?” The answer is that how whitespace is defined differs between the two.
java.lang.StringBuffer
java.lang.StringBuilder
Both these classes have a new compareTo()
method that takes a StringBuffer
/StringBuilder
and returns an int
. The lexographical comparison method is the same as the new compareTo()
method of the CharSequence
.
java.lang.Thread
No additional methods but the destroy()
and stop(Throwable)
methods have been removed. The stop()
method that takes no arguments is still present. This might present a compatibility issue.
java.nio.ByteBuffer
java.nio.CharBuffer
java.nio.DoubleBuffer
java.nio.FloatBuffer
java.nio.LongBuffer
java.nio.ShortBuffer
All these classes now have a mismatch()
method that finds and returns the relative index of the first mismatch between this buffer and a given buffer.
java.nio.channels.SelectionKey
-
int interestOpsAnd(int)
: Atomically sets this key’s interest set to the bitwise intersection (“and”) of the existing interest set and the given value. -
int interestOpsOr(int)
: Atomically sets this key’s interest set to the bitwise union (“or”) of the existing interest set and the given value.
java.nio.channels.Selector
-
int select(java.util.function.Consumer, long)
: Selects and performs an action on the keys whose corresponding channels are ready for I/O operations. The long parameter is a timeout. -
int select(java.util.function.Consumer)
: As above, except without the timeout. -
int selectNow(java.util.function.Consumer)
: As above, except it is non-blocking.
java.nio.file.Files
-
String readString(Path)
: Reads all content from a file into a string, decoding from bytes to characters using the UTF-8 charset. -
String readString(Path, Charset)
: As above, except decoding from bytes to characters using the specified Charset. -
Path writeString(Path, CharSequence, java.nio.file. OpenOption[]
:Write a CharSequence to a file. Characters are encoded into bytes using the UTF-8 charset. -
PathwriteString(Path, CharSequence, java.nio.file. Charset, OpenOption[]
: As above, exceptCharacters
are encoded into bytes using the specified Charset.
java.nio.file.Path
-
Path of(String, String[])
: Returns aPath
by converting a path string, or a sequence of strings that when joined form a path string. -
Path of(net.URI)
: Returns aPath
by converting a URI.
java.util.Collection
-
Object[] toArray(java.util.function.IntFunction)
: Returns an array containing all of the elements in this collection, using the provided generator function to allocate the returned array.
java.util.concurrent.PriorityBlockingQueue
java.util.PriorityQueue
-
void forEach(java.util.function.Consumer)
: Performs the given action for each element of the Iterable until all elements have been processed or the action throws an exception. -
boolean removeAll(java.util.Collection)
: Removes all of this collection’s elements that are also contained in the specified collection (optional operation). -
boolean removeIf(java.util.function.Predicate)
: Removes all of the elements of this collection that satisfy the given predicate. -
boolean retainAll(java.util.Collection)
: Retains only the elements in this collection that are contained in the specified collection (optional operation).
java.util.concurrent.TimeUnit
-
long convert(java.time.Duration)
: Converts the given time duration to this unit.
java.util.function.Predicate
-
Predicate not(Predicate)
. Returns a predicate that is the negation of the supplied predicate.
This is one of my favourite new APIs in JDK 11. As an example, you can convert this code:
lines.stream()
.filter(s -> !s.isBlank())
to
lines.stream()
.filter(Predicate.not(String::isBlank))
And, if we use a static import, it becomes:
lines.stream()
.filter(not(String::isBlank))
Personally, I think this version is more readable and easier to understand.
java.util.Optional
java.util.OptionalInt
java.util.OptionalDouble
java.util.OptionalLong
-
boolean isEmpty()
:If a value is not present, it returns true, otherwise it is false.
java.util.regex.Pattern
-
Predicate asMatchPredicate()
: I think this could be a hidden gem in the new JDK 11 APIs. It creates a predicate that tests if this pattern matches a given input string.
java.util.zip.Deflater
-
int deflate(ByteBuffer)
: Compresses the input data and fills the specified buffer with compressed data. -
int deflate(ByteBuffer, int)
: Compresses the input data and fills the specified buffer with compressed data. Returns the actual number of bytes of data compressed. -
void setDictionary(ByteBuffer)
: Sets the preset dictionary for compression to the bytes in the given buffer. This is an overloaded form of an existing method that can now accept a ByteBuffer, rather than a byte array. -
void setInput(ByteBuffer)
: Sets input data for compression. Also an overloaded form of an existing method.
java.util.zip.Inflater
-
int inflate(ByteBuffer)
: Uncompresses bytes into the specified buffer. Returns the actual number of bytes uncompressed. -
void setDictionary(ByteBuffer)
: Sets the preset dictionary to the bytes in the given buffer. An overloaded form of an existing method. -
void setInput(ByteBuffer)
: Sets input data for decompression. An overloaded form of an existing method.
javax.print.attribute.standard.DialogOwner
- This is a new class in JDK 11 and is an attribute class used to support requesting a print or page setup dialog be kept displayed on top of all windows or some specific window.
javax.swing.DefaultComboBoxModel
javax.swing.DefaultListModel
-
void addAll(Collection)
: Adds all of the elements present in the collection. -
void addAll(int, Collection)
: Adds all of the elements present in the collection, starting from the specified index.
javax.swing.ListSelectionModel
-
int[] getSelectedIndices()
: Returns an array of all of the selected indices in the selection model in increasing order. -
int getSelectedItemsCount()
: Returns the number of selected items.
jdk.jshell.EvalException
-
jshell.JShellException getCause()
: Returns the wrapped cause of the throwable in the executing client represented by thisEvalException
or null if the cause is non-existent or unknown.
Like what you see? Click here for Part 2.
Published at DZone with permission of Simon Ritter, DZone MVB. See the original article here.
Opinions expressed by DZone contributors are their own.
Comments