With Platform Module System, New Tools, New Core Libraries, Client Technologies and Languages Updates …, we all will be interested in how it makes many cool things for development.
*Note: To configure your IDE for working with Java 9, please visit:
How to configure Java 9 Support for Oxygen (4.7)
I. Java Platform Module System
Java 9 Module System, which is developed under Project Jigsaw, comes to us with the specific goal: to provide reliable configuration and strong flexible encapsulation. That helps application developers, library developers, or Java SE Platform implementors more easilier create a scalable platform, make greater platform integrity, and improve performance.
What is Module?
A module is a named, self-describing collection of:
– code: packages containing types (Java classes, interfaces…)
– data: resources and other kinds of static information.
In summary:
– Class contains fields, methods.
– Package contains Classes, Enums, Interfaces, configuration files…
– Module contains Package and Other data resources.
Module system mechanism provides Readability and Accessibility that control how a module can read others and to be accessed by others.
There are three kinds of module: named module, unnamed module, automatic module.
Java has a java.util.ServiceLoader class that helps to locate service providers at runtime by searching in class path. Now we can also specify service providers and users defined in modules.
>> More details at: Java 9 Module System
II. Tools
1. Jshell – The Java Shell
Java 9 provides an interactive REPL (Read-Eval-Print Loop) tool to test code snippets rapidly without a test project or main method. So we can learn or evaluate Java features easily.
Now we don’t need to create Java Project or define a public static void main(String[] args)
method for testing code. Just write and run immediately.
>> More details at: Java 9 JShell – REPL
2. Unified JVM Logging
Java 9 provides a common logging system for JVM components with extremely detailed level, an infrastructure to do the logging. With new command-line option -Xlog
for all logging followed settings, Unified JVM Logging gives us a precise, easy-to-configure tool to do a root cause analysis of complex system-level JVM components.
– Log messages are categorized using tags (os, gc, modules…). One message can have multiple tags (tag-set).
– Logging levels: error, warning, info, debug, trace and develop.
– Output supports 3 types: stdout, stderr, or a text file.
– Messages can be “decorated” with: time, uptime, pid, tid, level, tags…
>> More details at: Java 9 Unified JVM Logging
3. HTML5 Javadoc
Javadoc is the tool that can generate documentation for API in HTML format. In previous version of JDK, it’s HTML 4.01 – an old standard. JDK 9 Javadoc now supports to generate HTML5 markup, improves search capability and Doclint.
3.1– In JDK 9 which supports HTML5, we just need to add -html5
parameter:
javadoc -sourcepath "E:\Eclipse Java 9\Java9HTML5Javadoc\src" com.javasampleapproach.html5doc -d E:\home\html -html5
3.2– A search box is available on the site that can be used to search for program elements, tagged words and phrases within the documentation. The search functionality is implemented locally and not rely on any server-side computational resources.
3.3– -Xdoclint
enables recommended checks for issues in Javadoc comments: bad references, lack of accessibility, missing comments, syntax error and missing HTML tags. By default, -Xdoclint
is enabled. We can disable it by -Xdoclint:none
.
This is an example for syntax check:
>> More details at: Java 9 HTML5 Javadoc
III. Language Updates
1. try-with-resources Improvement
Java 7 introduces a new approach for closing resources by try-with-resources statement. After that, Java 9 try-with-resources makes an improved way of writing code. Now we can simplify our code and keep it cleaner and clearer.
// BufferedReader is declared outside try() block BufferedReader br = new BufferedReader(new FileReader("C://readfile/input.txt")); // Java 9 make it simple try (br) { String line; while (null != (line = br.readLine())) { // processing each line of file System.out.println(line); } } catch (IOException e) { e.printStackTrace(); }
>> More details at: Java 9 try-with-resources Improvement
2. Private Interface Method
Java 8 provides 2 new features for Interface: default methods and static methods.
But, it still makes us uncomfortable because:
-> We don’t want to public that method, it is just an inner private method which handles a specific function.
-> We don’t want another interface or class which implements this interface can access or inherit that method.
Java 9 Private Interface Method solves the problems by providing a new feature for interface: private method/private static method. Now we can avoid duplicate code and keep encapsulation for interface.
public interface IMyInterface { private void method1(String arg) { // do something } private static void method2(Integer arg) { // do something } }
>> More details at: Java 9 Private Interface Method
3. Diamond Operator
Java 7 has a new feature called Diamond Operator which helps to make code more readable, but it is still limited with Anonymous Inner Classes.
We will get the compile error: ‘<>‘ cannot be used with anonymous classes if writing code like this:
MyHandlerintHandler = new MyHandler<>(10) { // Anonymous Class }; MyHandler> handler = new MyHandler<>(""One hundred") { // Anonymous Class };
Java 9 allows the Diamond Operator for Anonymous Inner Classes:
MyHandlerintHandler = new MyHandler<>(1) { @Override public void handle() { // handling code... } }; MyHandler extends Integer> intHandler1 = new MyHandler<>(10) { @Override void handle() { // handling code... } }; MyHandler> handler = new MyHandler<>("One hundred") { @Override void handle() { // handling code... } }; }
>> More details at: Java 9 Diamond Operator for Anonymous Inner Classes
IV. New Core Libraries
1. Process API
There are new ways of retrieving process information: all processes, current process, children processes and destroying process with Java 9 Process API.
// current Process ProcessHandle processHandle = ProcessHandle.current(); processHandle.getPid(); processHandle.isAlive(); processHandle.children().count(); processHandle.supportsNormalTermination(); ProcessHandle.Info processInfo = processHandle.info(); processInfo.arguments(); processInfo.command(); processInfo.totalCpuDuration(); processInfo.user(); // all Processes StreamprocessStream = ProcessHandle.allProcesses(); // destroy Process processHandle.destroy();
>> More details at: Java 9 Process API
2. Platform Logging API and Service
Java 9 defines a minimal logging API which platform classes can use to log messages, together with a service interface for consumers of those messages.
An implementation of LoggerFinder
is loaded with help of java.util.ServiceLoader API using system class loader. Basing on this implementation, an application/framework can plug in its own external logging backend, without configuring java.util.logging or that backend.
We can pass the class name or module (related to specific Logger) to the LoggerFinder
so that the LoggerFinder
can know which logger to return.
If no concrete implementation is found, JDK default LoggerFinder
implementation will be used. java.util.logging (in java.logging module) now becomes backend. So log messages will be routed to java.util.logging.Logger.
We obtain loggers that are created from the LoggerFinder
using factory methods of the System class:
package java.lang; ... public class System { System.Logger getLogger(String name) { ... } System.Logger getLogger(String name, ResourceBundle bundle) { ... } }
>> More details and example at: Java 9 Platform Logging API and Service
3. CompletableFuture API Enhancements
To improve Java Future, Java 8 provides CompletableFuture which can execute some code whenever its ready. Now Java 9 improves CompletableFuture API that supports delay and timeout.
future.completeAsync(supplier, CompletableFuture.delayedExecutor(3, TimeUnit.SECONDS)) .thenAccept(result -> System.out.println("accept: " + result)); // other statements
// TIMEOUT = 3; // doWork() takes 5 seconds to finish CompletableFuturefuture = doWork("JavaSampleApproach") .orTimeout(TIMEOUT, TimeUnit.SECONDS) .whenComplete((result, error) -> { if (error == null) { System.out.println("The result is: " + result); } else { System.out.println("Sorry, timeout in " + TIMEOUT + " seconds"); } });
// TIMEOUT = 3; // doWork() takes 5 seconds to finish CompletableFuturefuture = doWork("JavaSampleApproach") .completeOnTimeout("JavaTechnology", TIMEOUT, TimeUnit.SECONDS) .whenComplete((result, error) -> { if (error == null) { System.out.println("The result is: " + result); } else { // this statement will never run. System.out.println("Sorry, timeout in " + TIMEOUT + " seconds."); } });
>> More details at: Java 9 CompletableFuture API Improvements – Delay and Timeout Support
4. Reactive Streams – Flow API
Java 9 introduces Reactive Streams under java.util.concurrent.Flow
that supports an interoperable publish-subscribe framework. At a glance:
@FunctionalInterface public static interface Publisher{ public void subscribe(Subscriber super T> subscriber); } public static interface Subscriber { public void onSubscribe(Subscription subscription); public void onNext(T item); public void onError(Throwable throwable); public void onComplete(); } public static interface Subscription { public void request(long n); public void cancel(); } public static interface Processor extends Subscriber , Publisher { }
The diagram below shows its behavior and how to implement Reactive Stream with new Flow API:
>> More details at:
– Java 9 Flow API – Reactive Streams
– Java 9 Flow API example – Publisher and Subscriber
– Java 9 Flow API example – Processor
– Java 9 FLow SubmissionPublisher – A Concrete Publisher
5. Factory Method for Collections: List, Set, Map
Java 9 provides new static factory methods for creating instances of collections and maps conveniently with small number of elements.
ListimmutableList = List.of("one", "two", "three"); Set immutableSet = Set.of("one", "two", "three"); Map immutableMap = Map.of(1, "one", 2, "two", 3, "three");
But the collections created with static factory method are immutable, so if we try to add/put more elements or null into them, we will get java.lang.UnsupportedOperationException
or java.lang.NullPointerException
.
>> More details at: Java 9 Factory Method for Collections: List, Set, Map
6. Enhanced Deprecation
There are new added methods of Java 9 @Deprecated
annotation: forRemoval()
and since()
.
An example with new @Deprecated annotation:
@Deprecated(since ="1.5", forRemoval = true)
>> More details at: Java 9 @Deprecated Enhancements
7. Stack-Walking API
Java 9 provides an efficient way of stack walking for lazy access, filtering stack trace with StackWalker
.
StackWalker
object allows us to traverse and access to stacks. It contains some useful and powerful methods:
publicT walk(Function super Stream , ? extends T> function); public void forEach(Consumer super StackFrame> action); public Class> getCallerClass();
The most important method is walk()
that helps:
+ open a StackFrame
stream for the current thread.
+ then apply the function with that StackFrame
stream.
>> More details at: Java 9 StackWalker
8. Other Improvements
8.1 Stream Improvements
Java 9 Stream comes with some small useful improvements for Asynchronous Programming with new added methods: iterate()
, takeWhile()
/dropWhile()
, ofNullable()
.
IntStream .iterate(1, i -> i < 20, i -> i * 2) .forEach(System.out::println);
//for ordered Stream Stream.of(1, 2, 3, 4, 5, 6).takeWhile(i -> i <= 3).forEach(System.out::println); // The result is: // 1 // 2 // 3 // for unordered Stream Stream.of(1, 6, 5, 2, 3, 4).takeWhile(i -> i <= 3).forEach(System.out::println); // The result is: // 1
//for ordered Stream Stream.of(1, 2, 3, 4, 5, 6).dropWhile(i -> i <= 3).forEach(System.out::println); // It drops (1,2,3), the result is: // 4 // 5 // 6 //for unordered Stream Stream.of(1, 6, 5, 2, 3, 4).dropWhile(i -> i <= 3).forEach(System.out::println); // It drops (1), the result is: // 6 // 5 // 2 // 3 // 4
// numbers [1,2,3,null] // mapNumber [1 - one, 2 - two, 3 - three, null - null] ListnewstringNumbers = numbers.stream() .flatMap(s -> Stream.ofNullable(mapNumber.get(s))) .collect(Collectors.toList()); // The result is: // [one, two, three]
>> More details at: Java 9 Stream Improvements
8.2 Optional Improvements
Java 9 provides new Optional::stream
to work on Optional
objects lazily, it returns a stream of either zero or one/more elements. It also checks empty element automatically and removes it.
// streamOptional(): [(Optional.empty(), Optional.of("one"), Optional.of("two"), Optional.of("three")] ListnewStrings = streamOptional() .flatMap(Optional::stream) .collect(Collectors.toList()); // Result: newStrings[one, two, three]
Instead of using isPresent()
and orElse()
to make code more clearlier and handle "else" case, now we have ifPresentOrElse()
method with Java 9:
Optionalresult3 = getOptionalEmpty(); result3.ifPresentOrElse( x -> System.out.println("Result = " + x), () -> System.out.println("return " + result2.orElse(-1) + ": Result not found.")); // return -1: Result not found.
or()
method checks if a value is present, it will return an Optional
for the value, otherwise return another Optional which is produced by the supplying function.
Optionalresult = getOptionalEmpty() // Empty Optional object .or(() -> getAnotherOptionalEmpty()) // Empty Optional object .or(() -> getOptionalNormal()) // this return an Optional with real value 42 .or(() -> getAnotherOptionalNormal()); // this return an Optional with real value 99 // Result: Optional[42]
>> More details at: Java 9 Optional Improvements
V. Client Technologies
1. Multi-Resolution Images
The new API which is defined in the java.awt.image
package can help us:
– Encapsulate many images with different resolutions into an image as its variants.
– Get all variants in the image.
– Get a resolution-specific image variant – the best variant to represent the logical image at the indicated size based on a given DPI metric.
>> More details at: Java 9 Multi-Resolution Images
2. TIFF Image I/O Plugins
In earlier version of Java, Image I/O Framework javax.imageio
provides a standard way to plug-in image codecs for some formats such as PNG and JPEG. But TIFF is still missing from this set. It was packaged in com.sun.media.imageio.plugins.tiff
before. Java 9 TIFF Image I/O plugins has a new package called javax.imageio.plugins.tiff
which is renamed from com.sun.media.imageio.plugins.tiff
.
The package contains some classes that support the built-in TIFF reader and writer plug-ins. It includes:
- Some classes representing common additional tags and the set of tags found in baseline TIFF specification, Exif IFD, TIFF-F (RFC 2036) file, GeoTIFF IFD.
- TIFFImageReadParam
: an extension of ImageReadParam
which can specify which metadata tags are allowed to be read and set some destination properties.
>> More details at: Java 9 TIFF Image I/O plugins
VI. Internationalization
1. Unicode 8.0
Java 8 supported Unicode 6.2.
Java 9 now supports up to Unicode 8.0 standards with 10,555 characters, 29 scripts, and 42 blocks.
2. UTF-8 Properties Files
In previous releases, ISO-8859-1 encoding was used when loading property resource bundles (PropertyResourceBundle
- constructing its instance from an InputStream
requires that the input stream be encoded in ISO-8859-1). But using ISO-8859-1 is not a convenient way to represent non-Latin characters.
In Java 9, properties files are loaded in UTF-8 encoding.
If there is an issue, consider the following options:
- convert the properties file into UTF-8 encoding.
- specify the runtime system property:
java.util.PropertyResourceBundle.encoding=ISO-8859-1
>> More details at: Java 9 Internationalization Enhancements
3. Default Locale Data Change
In JDK 8 and previous releases, JRE is the default locale data. JDK 9 sets CLDR (the locale data provided by the Unicode Common Locale Data Repository project) as highest priority by default.
This is how we select locale data source in the preferred order using java.locale.providers
system property. If a provider is failed to request locale data, the next provider will be processed:
java.locale.providers=COMPAT,CLDR,HOST,SPI
If we don't set the property, default behaviour is:
java.locale.providers=CLDR,COMPAT,SPI
>> More details at: Java 9 Internationalization Enhancements
Latest Posts: Java 9