Hello, I'm looking at the mountain.
This article is included in Java advanced journey from small worker to expert In a series of columns.
Since 2017, the Java version update strategy has changed from a new version every two years to a new version every six months to quickly verify new features and promote the development of Java. from <JVM Ecosystem Report 2021> It can be seen that nearly half of the current development environments use Java 8, and nearly half of the people have moved to Java 11. I believe the proportion will change with the release of Java 17.
Therefore, prepare a series to explain the new features of each version with examples.
summary
Compared to Java8 , Java 9 does not add syntax sugar, but its added features are also very practical, such as Jigsaw modularization, JShell, publish subscribe framework, GC, etc. This article will introduce some new features quickly and at a high level. Complete features can participate https://openjdk.java.net/projects/jdk9/.
It should be noted here that Java 9 is not a long-term support version, and the current situation is from now on, so the author is lazy. The sample code of the article is written under Java 11, which may be different from the definition in Java 9. However, it's nothing. After all, we still give priority to the long-term support version when we really use it.
Jigsaw modular
Modularity is a relatively large update, which makes the previous all in one Java package split into several modules. This modular system provides functions similar to OSGi framework system. For example, multiple modules can be developed independently, referenced and integrated on demand, and finally assembled into a complete function.
Modules have the concept of dependency. They can export functional API s and hide implementation details.
Another advantage is that the JVM can be used on demand, which can reduce the volume of Java running package and allow the JVM to run on devices with smaller memory. At that time, the original intention of JVM was to make hardware, which was not forgotten.
In addition, com.com in the JVM sun.* Internal API s such as, are more closed, and calls are no longer allowed, which improves kernel security.
When using, we need to define a module info in the top-level directory of java code java file, used to describe module information:
module cn.howardliu.java9.modules.car { requires cn.howardliu.java9.modules.engines; exports cn.howardliu.java9.modules.car.handling; }
The information described above is: module CN howardliu. java9. modules. Car needs to rely on the module CN howardliu. java9. modules. Engines and export the module CN howardliu. java9. modules. car. handling.
For more information, see the OpenJDK guidelines https://openjdk.java.net/projects/jigsaw/quick-start , the use of Jigsaw module will be introduced separately later, and the content will be posted in the comment area.
New HTTP client
This is a long-awaited function. Finally, there is an official API to replace the old and difficult HttpURLConnection. However, in Java 9, the new HTTP client is placed in the incubation module (see details) https://openjdk.java.net/jeps/110 ).
There are many problems with the old HTTP client. We basically use the third-party HTTP library when developing, such as Apache HttpClient, Netty, Jetty, etc.
There are many targets for the new HTTP client. After all, so many pearls and jade are ahead. If it is still made into a lump, it is specified that it will be laughed to death. Therefore, the new HTTP client lists 16 goals, including ease of use, printing key information, WebSocket, HTTP/2, HTTPS/TLS, good performance, non blocking API, etc.
Let's take a brief look first:
final String url = "https://postman-echo.com/get"; final HttpRequest request = HttpRequest.newBuilder() .uri(new URI(url)) .GET() .build(); final HttpResponse<String> response = HttpClient.newHttpClient() .send(request, HttpResponse.BodyHandlers.ofString()); final HttpHeaders headers = response.headers(); headers.map().forEach((k, v) -> System.out.println(k + ":" + v)); System.out.println(response.statusCode()); System.out.println(response.body());
The new HTTP client can be used normally in Java 11. The above code is also written in Java 11. The API is in Java net. HTTP package.
Improved process API
The process API provided in Java 9 can control and manage operating system processes. In other words, you can manage the current process in your code, or even destroy the current process.
Process information
This function is provided by Java Lang. processhandle. Let's see how to use it:
final ProcessHandle self = ProcessHandle.current(); final long pid = self.pid(); System.out.println("PID: " + pid); final ProcessHandle.Info procInfo = self.info(); procInfo.arguments().ifPresent(x -> { for (String s : x) { System.out.println(s); } }); procInfo.commandLine().ifPresent(System.out::println); procInfo.startInstant().ifPresent(System.out::println); procInfo.totalCpuDuration().ifPresent(System.out::println);
java.lang.ProcessHandle.Info provides rich process information
Destruction process
We can also use Java Lang. processhandle #destroy method destroys the process. Let's demonstrate how to destroy the child process:
ProcessHandle.current().children() .forEach(procHandle -> { System.out.println(procHandle.pid()); System.out.println(procHandle.destroy()); });
After Java8, we will find that the API provided by Java uses Optional, Stream and other functions, and * * Eating your own dog food * * is also worth learning.
Other minor changes
Java 9 has also made some changes to the existing functions. Let's take a look at them.
Improve try with resources
Starting from Java 7, we can use the try with resources syntax to automatically close resources, all of which implement Java Lang. autoclosable interface, which can be used as a resource. However, there is a limitation that each resource needs to declare a new variable.
That's it:
public static void tryWithResources() throws IOException { try (FileInputStream in2 = new FileInputStream("./")) { // do something } }
It's quite convenient for this kind of direct use, but what if it needs to be defined by some column methods? You have to write it like this:
final Reader inputString = new StringReader("www.howardliu.cn Look at the mountain"); final BufferedReader br = new BufferedReader(inputString); // Some other logic try (BufferedReader br1 = br) { System.out.println(br1.lines()); }
In Java 9, if the resource is final defined or equivalent to the final variable, you don't need to declare a new variable name. You can use it directly in try with resources:
final Reader inputString = new StringReader("www.howardliu.cn Look at the mountain"); final BufferedReader br = new BufferedReader(inputString); // Some other logic try (br) { System.out.println(br.lines()); }
Improved diamond operator
The diamond operator (i.e. < >) is introduced in Java 7 and can simplify the writing of generic types, such as:
Map<String, List<String>> strsMap = new TreeMap<String, List<String>>();
The TreeMap type on the right can be inferred from the generic definition on the left. With the help of the diamond operator, it can be simplified to:
Map<String, List<String>> strsMap = new TreeMap<>();
Looking at the mountain will be much simpler. The writing of < > is the diamond operator.
However, this approach does not apply to anonymous inner classes. For example, there is an abstract class:
abstract static class Consumer<T> { private T content; public Consumer(T content) { this.content = content; } abstract void accept(); public T getContent() { return content; } }
Before Java 9, if you want to implement anonymous inner classes, you need to write:
final Consumer<Integer> intConsumer = new Consumer<Integer>(1) { @Override void accept() { System.out.println(getContent()); } }; intConsumer.accept(); final Consumer<? extends Number> numConsumer = new Consumer<Number>(BigDecimal.TEN) { @Override void accept() { System.out.println(getContent()); } }; numConsumer.accept(); final Consumer<?> objConsumer = new Consumer<Object>("Look at the mountain") { @Override void accept() { System.out.println(getContent()); } }; objConsumer.accept();
After Java 9, you can use the diamond operator:
final Consumer<Integer> intConsumer = new Consumer<>(1) { @Override void accept() { System.out.println(getContent()); } }; intConsumer.accept(); final Consumer<? extends Number> numConsumer = new Consumer<>(BigDecimal.TEN) { @Override void accept() { System.out.println(getContent()); } }; numConsumer.accept(); final Consumer<?> objConsumer = new Consumer<>("Look at the mountain") { @Override void accept() { System.out.println(getContent()); } }; objConsumer.accept();
Private interface method
If the diamond operator is a concise and readable code, the private method of the interface is a more practical extension.
Before Java 8, interfaces can only have constants and abstract methods. If you want to have a specific implementation, you can only use abstract classes. However, Java is single inheritance, and many scenarios will be limited.
After Java 8, default methods and static methods can be defined in the interface, and many extensions are provided. However, these methods are public methods and are completely exposed to the outside world. If there is a method that only wants to be used in the interface without exposing it, there is no way. This problem has been solved in Java 9. We can use the private modifier to limit its scope.
For example:
public interface Metric { // constant String NAME = "METRIC"; // Abstract method void info(); // Private method private void append(String tag, String info) { buildMetricInfo(); System.out.println(NAME + "[" + tag + "]:" + info); clearMetricInfo(); } // Default method default void appendGlobal(String message) { append("GLOBAL", message); } // Default method default void appendDetail(String message) { append("DETAIL", message); } // Private static method private static void buildMetricInfo() { System.out.println("build base metric"); } // Private static method private static void clearMetricInfo() { System.out.println("clear base metric"); } }
JShell
JShell is the REPL(Read Eval Print Loop) environment provided by the Java language. This environment has long been available in languages such as Python and Node, which can easily execute Java statements and quickly verify some syntax and functions.
$ jshell | Welcome JShell -- Version 13.0.9 | To get an overview of this version, type:/help intro
We can use / help directly to view the command
jshell> /help | typing Java Language expression, statement or declaration. | Or type one of the following commands: | /list [<Name or id>|-all|-start] | Lists the sources you typed | /edit <Name or id> . A lot of content, in view of space, should be hidden first
Let's look at some simple operations:
jshell> "This is a test.".substring(5, 10); $2 ==> "is a " jshell> 3+1 $3 ==> 4
You can also create methods:
jshell> int mulitiTen(int i) { return i*10;} | Method created mulitiTen(int) jshell> mulitiTen(3) $6 ==> 30
To exit the JShell, enter:
jshell> /exit | bye
JCMD new subcommand
jcmd is used to send diagnostic commands to local jvm processes. This command is a command line tool provided from JDK7 and is often used to quickly locate online environment faults.
After JDK9, some new subcommands are provided to view the list of all classes loaded in the JVM and their inheritance structures. For example:
$ jcmd 22922 VM.class_hierarchy -i -s java.net.Socket 22922: java.lang.Object/null |--java.net.Socket/null | implements java.io.Closeable/null (declared intf) | implements java.lang.AutoCloseable/null (inherited intf) | |--sun.nio.ch.SocketAdaptor/null | | implements java.lang.AutoCloseable/null (inherited intf) | | implements java.io.Closeable/null (inherited intf)
The first parameter is the process ID, which is used to perform diagnosis for this process. We can also use set_ The vmflag parameter modifies the JVM parameters online without restarting the JVM process.
Sometimes you also need to view the virtual machine parameter options and current values of the current process: jcmd 22922 VM flags -all.
Multi resolution image API
The multi-resolution image API is defined in Java 9. We can easily operate and display images with different resolutions. java.awt.image.MultiResolutionImage encapsulates a set of images with different resolutions into a single object. java. awt. The graphics class obtains variables from a multi-resolution image based on the currently displayed DPI metric and the transformation of any application.
The following are the main operation methods of multi-resolution image:
- Image getResolutionVariant(double destImageWidth, double destImageHeight): obtain an image variant of a specific resolution - represents a logical image of a specific size with a known resolution unit of DPI, and this image is the best variant.
- List < Image > getresolutionvariants(): returns a list of image variants of readable resolution.
Let's look at the following applications:
final List<Image> images = List.of( ImageIO.read(new URL("https://static.howardliu.cn/about/kanshanshuo_2.png")), ImageIO.read(new URL("https://static.howardliu.cn/about/hellokanshan.png")), ImageIO.read(new URL("https://static.howardliu.cn/about/evil%20coder.jpg")) ); // Read all pictures final MultiResolutionImage multiResolutionImage = new BaseMultiResolutionImage(images.toArray(new Image[0])); // Get all resolutions of the picture final List<Image> variants = multiResolutionImage.getResolutionVariants(); System.out.println("Total number of images: " + variants.size()); for (Image img : variants) { System.out.println(img); } // Obtain the corresponding image resolution according to different sizes Image variant1 = multiResolutionImage.getResolutionVariant(100, 100); System.out.printf("\nImage for destination[%d,%d]: [%d,%d]", 100, 100, variant1.getWidth(null), variant1.getHeight(null)); Image variant2 = multiResolutionImage.getResolutionVariant(200, 200); System.out.printf("\nImage for destination[%d,%d]: [%d,%d]", 200, 200, variant2.getWidth(null), variant2.getHeight(null)); Image variant3 = multiResolutionImage.getResolutionVariant(300, 300); System.out.printf("\nImage for destination[%d,%d]: [%d,%d]", 300, 300, variant3.getWidth(null), variant3.getHeight(null)); Image variant4 = multiResolutionImage.getResolutionVariant(400, 400); System.out.printf("\nImage for destination[%d,%d]: [%d,%d]", 400, 400, variant4.getWidth(null), variant4.getHeight(null)); Image variant5 = multiResolutionImage.getResolutionVariant(500, 500); System.out.printf("\nImage for destination[%d,%d]: [%d,%d]", 500, 500, variant5.getWidth(null), variant5.getHeight(null));
Variable Handles
The API of Variable Handles is mainly used to replace some functions of java.util.concurrent.atomic package and sun.misc.Unsafe class, and provides a series of standard memory barrier operations to control memory sorting more finely. A variable handle is a variable The type reference of (any field, array element, static table, etc.) supports the access to these type variables under different access models, including simple read/write access, volatile type read/write access, CAS (compare and swap), etc.
This part involves reflection, inline, concurrency and other contents, which will be introduced separately later. The article will eventually be published in Java advanced journey from small worker to expert Please pay attention.
Publish subscribe framework
Java. Net added in Java 9 util. concurrent. Flow supports the publish subscribe framework of responsive API s, which provide interoperability between many asynchronous systems running on the JVM. We can customize components with the help of SubmissionPublisher.
You can view the content of the responsive API first http://www.reactive-streams.org/ The content will be introduced separately later, and the article will eventually be published in Java advanced journey from small worker to expert Please pay attention. How do you feel that you have planed so many pits for yourself? You have to hurry up and fill the pits.
Unified JVM logging
In this release, a common logging system is introduced for all components of the JVM. It provides the basis for logging. This function is specified through the - Xlog startup parameter, and many tags are defined to define different types of logs, such as GC (garbage collection), compiler, threads, etc. for example, we define the debug level GC log, which is stored in the gc.log file:
java -Xlog:gc=debug:file=gc.log:none
Because there are many parameters, we can view the specific defined parameters through java -Xlog:help. Moreover, the log configuration can be dynamically modified through the jcmd command. For example, we modify the log output file to gc_other.log:
jcmd ${PID} VM.log output=gc_other.log what=gc
New API
Immutable set
Java. Net added in Java 9 util. List. of(),java.util.Set.of(),java.util.Map.of() series of methods, you can create immutable collections in one line of code. Before Java 9, if we want to initialize a collection with a specified value, we need to execute a bunch of add or put methods, or rely on the guava framework.
Moreover, these collection objects are variable. If we pass values into a method, we have no way to control that the values of these collections will not be modified. After Java 9, we can initialize an immutable collection with initial values with the help of the definitions in immutable collections. If you modify these objects (add elements, delete elements), you will throw an unsupported operationexception.
It must be mentioned here that Java developers also consider performance and provide different implementation classes for different numbers of collections:
- List12, Set12 and Map1 are specially used for scenes with a small number of elements (2 for list and Set and 1 for Map)
- List n, SetN and MapN are used in scenes with a large amount of data (there are more than 2 lists and sets, and there is more than 1 pair for Map)
Improved Optional class
In Java 9, three practical methods have been added for Optional: stream, ifpresentoelse, or.
Stream is to convert an option into a stream. If the option contains a value, the stream containing the value will be returned. Otherwise, the stream will be returned empty(). For example, we have a collection that needs to filter non empty data. Before Java 9, it was written as follows:
final List<Optional<String>> list = Arrays.asList( Optional.empty(), Optional.of("Look at the mountain"), Optional.empty(), Optional.of("Look at the cottage on the mountain")); final List<String> filteredList = list.stream() .flatMap(o -> o.isPresent() ? Stream.of(o.get()) : Stream.empty()) .collect(Collectors.toList());
After Java 9, we can use the stream method:
final List<String> filteredListJava9 = list.stream() .flatMap(Optional::stream) .collect(Collectors.toList());
Ifpresentoelse: if an option contains a value, the function action is called on the value it contains, that is, action Accept (value), which is consistent with ifPresent method; If Optional does not contain a value, emptyAction will be called, that is, emptyAction run(). The effects are as follows:
Optional<Integer> optional = Optional.of(1); optional.ifPresentOrElse(x -> System.out.println("Value: " + x), () -> System.out.println("Not Present.")); optional = Optional.empty(); optional.ifPresentOrElse(x -> System.out.println("Value: " + x), () -> System.out.println("Not Present.")); // The output result is: // Author: kanshan // nameless
or: if the value exists, return the value specified by option; otherwise, return a preset value. The effects are as follows:
Optional<String> optional1 = Optional.of("Look at the mountain"); Supplier<Optional<String>> supplierString = () -> Optional.of("nameless"); optional1 = optional1.or(supplierString); optional1.ifPresent(x -> System.out.println("Author:" + x)); optional1 = Optional.empty(); optional1 = optional1.or(supplierString); optional1.ifPresent(x -> System.out.println("Author:" + x)); // The output result is: // Author: kanshan // Author: Anonymous
Summary at the end of the paper
This article introduces the new features of Java 9. A complete list of features can be found from https://openjdk.java.net/projects/jdk9/ see. The article also digs several holes for itself. Due to the length, there is no way to expand. All the detailed descriptions of these functions that need to be expanded will be supplemented after the completion of the new feature series from Java 8 to Java 17. The blog will be published on Java advanced journey from small worker to expert In a series of columns.
Recommended reading
- Master the 24 operations of Collectors in Java8 Stream
- Master the six Optional operations of Java 8
- Use Lambda expression to realize super sorting function
- Java 8 time library (1): introduces time classes and common API s in Java 8
- Java 8 time library (2): Date and LocalDate or LocalDateTime are converted to each other
- Java 8 time library (3): start using the time class in Java 8
- Java 8 time library (4): check whether the date string is legal
- New features in Java 8
Hello, I'm looking at the mountain. Swim in the code world and enjoy life. If the article is helpful to you, please like, collect and pay attention to it. I also compiled some excellent learning materials, and I would like to pay attention to the official account of "the mountain view cabin" and get the reply to "information".
Personal homepage: https://www.howardliu.cn
Personal blog: Java updates new features every six months. If you don't master them, you'll fall behind: the new features of Java 9
CSDN home page: https://kanshan.blog.csdn.net/
CSDN blog: Java updates new features every six months. If you don't master them, you'll fall behind: the new features of Java 9