“This is the 19th day of my participation in the First Challenge 2022. For details: First Challenge 2022”

Hello, I’m looking at the mountains.

This article is part of a series of columns on the Journey to Java Progression.

Starting in 2017, the Java version update policy was changed from a new release every two years to a new release every six months to quickly validate new features and drive The development of Java. As you can see from the JVM Ecosystem Report 2021, nearly half of the development environment currently uses Java8, and nearly half of the people have migrated to Java11, with the release of Java17 expected to change that ratio.

Therefore, prepare a series with examples to illustrate the new features in each release.

An overview of the

Java9 doesn’t have any new syntactic sugar compared to Java8, but it does have useful features like Jigsaw modularity, JShell, publish-subscribe framework, GC, and so on. This article will introduce fast, high level of some new features, the characteristics of complete can attend openjdk.java.net/projects/jd…

It is important to note that since Java9 is not a long-term support release and is not currently available, I have been so lazy that the sample code in this article is written under Java11, which may be a bit different from the definition in Java9, but that is ok, as the long-term support version is the priority when we actually use it.

Jigsaw modularity

Modularity is a major update that separates the previous All-in-one Java package into several modules. This modular system provides functionality similar to OSGi framework systems, such as multiple modules that can be developed independently, referenced on demand, integrated on demand, and finally assembled into a complete function.

Modules have the concept of dependencies, the ability to export functional apis, and the ability to hide implementation details.

Another benefit is on-demand use of the JVM, which reduces the size of the Java run package and allows the JVM to run on devices with less memory. The ORIGINAL purpose of the JVM was to be hardware, and that’s true.

In addition, internal apis in the JVM, such as com.sun.*, are more closed and no longer allowed to be called, improving kernel security.

To use it, we need to define a module-info.java file in the top-level directory of the Java code that describes module information:

module cn.howardliu.java9.modules.car {
    requires cn.howardliu.java9.modules.engines;
    exports cn.howardliu.java9.modules.car.handling;
}
Copy the code

The information described above is: Module cn. Howardliu. Java9. Modules. Cn. The car need to rely on module howardliu. Java9. Modules. Engines, and export modules. Cn howardliu. Java9. Modules. Car. Handling.

More information can be viewed its guidance openjdk.java.net/projects/ji… Jigsaw module, content will be posted to the comments section.

Brand new HTTP client

This has been a long time coming, and there is finally an official API to replace the old and difficult HttpURLConnection. In Java9, simply, the new HTTP client is in the incubation module (specific information can view openjdk.java.net/jeps/110).

There are a lot of problems with the old HTTP client. When we develop it, we basically use third-party HTTP libraries, such as Apache HttpClient, Netty, Jetty, etc.

The new HTTP client has a lot of goals, after all, so many beads and jade in the front, if it is still made of a lump, specified is to be laughed to death. So the new HTTP client lists 16 goals, including ease of use, printing critical information, WebSocket, HTTP/2, HTTPS/TLS, good performance, non-blocking apis, and more.

Let’s take a quick look:

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());
Copy the code

The new HTTP client is now available in Java11, where the above code was written and the API is in the java.net.http package.

Improved process API

Process apis provided in Java9 to control and manage operating system processes. That is, the current process can be managed in code and even destroyed.

Process information

This feature is provided by java.lang.ProcessHandle. Let’s see how it works:

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);Copy the code

Java. Lang. ProcessHandle. Provides a wealth of information process in the Info

Destruction of the process

We can also destroy a process using the java.lang.ProcessHandle#destroy method.

ProcessHandle.current().children()
        .forEach(procHandle -> {
            System.out.println(procHandle.pid());
            System.out.println(procHandle.destroy());
        });
Copy the code

From Java8 onwards, Java provides apis that use Optional, Stream, etc. Eating your own dog food ** is also worth learning.

Other minor changes

Java9 also made some changes to existing functionality, so let’s take a look at what they are.

Improve the try – with – resources

Starting with Java7, we can use the try-with-resources syntax to automatically close resources, all of which implement the java.lang.AutoCloseable interface and can be used as resources. There is a limitation, however, that each resource needs to declare a new variable.

And that’s it:

public static void tryWithResources(a) throws IOException {
    try (FileInputStream in2 = new FileInputStream(". /")) {
        // do something}}Copy the code

This is easy for direct use, but what if it’s defined in a series of methods? It would look something like this:

final Reader inputString = new StringReader("Www.howardliu.cn see mountain");
final BufferedReader br = new BufferedReader(inputString);
// Some other logic
try (BufferedReader br1 = br) {
    System.out.println(br1.lines());
}
Copy the code

In Java9, you don’t have to declare a new variable name if the resource is defined as final or equivalent to a final variable. You can use it directly in try-with-resources:

final Reader inputString = new StringReader("Www.howardliu.cn see mountain");
final BufferedReader br = new BufferedReader(inputString);
// Some other logic
try (br) {
    System.out.println(br.lines());
}
Copy the code

Improved Diamond Operator

The diamond operator (i.e. <>) was introduced in Java7 to simplify writing generics, such as:

Map<String, List<String>> strsMap = new TreeMap<String, List<String>>();
Copy the code

The TreeMap type on the right can be inferred from the generic definition on the left, which can be simplified by the diamond operator:

Map<String, List<String>> strsMap = new TreeMap<>();
Copy the code

Looking at mountains is a lot simpler, and <> is written as the Diamond Operator.

But this doesn’t work for anonymous inner classes. Let’s say we have an abstract class:

abstract static class Consumer<T{
    private T content;

    public Consumer(T content) {
        this.content = content;
    }

    abstract void accept(a);

    public T getContent(a) {
        returncontent; }}Copy the code

Prior to Java9, to implement an anonymous inner class, you would write:

final Consumer<Integer> intConsumer = new Consumer<Integer>(1) {
    @Override
    void accept(a) { System.out.println(getContent()); }}; intConsumer.accept();final Consumer<? extends Number> numConsumer = new Consumer<Number>(BigDecimal.TEN) {
    @Override
    void accept(a) { System.out.println(getContent()); }}; numConsumer.accept();finalConsumer<? > objConsumer =new Consumer<Object>("Mountain") {
    @Override
    void accept(a) { System.out.println(getContent()); }}; objConsumer.accept();Copy the code

The diamond operator is available after Java9:

final Consumer<Integer> intConsumer = new Consumer<>(1) {
    @Override
    void accept(a) { System.out.println(getContent()); }}; intConsumer.accept();final Consumer<? extends Number> numConsumer = new Consumer<>(BigDecimal.TEN) {
    @Override
    void accept(a) { System.out.println(getContent()); }}; numConsumer.accept();finalConsumer<? > objConsumer =new Consumer<>("Mountain") {
    @Override
    void accept(a) { System.out.println(getContent()); }}; objConsumer.accept();Copy the code

Private interface methods

If the diamond operator is concise and readable code, the interface’s private methods are a useful extension.

Prior to Java8, interfaces could only have constants and abstract methods. To have a concrete implementation, you could only use abstract classes, but Java is a single inheritance and many scenarios are limited.

After Java8, default and static methods can be defined in interfaces, providing many extensions. But these methods are all public methods and are completely exposed. If you have a method that you want to use only in the interface, but don’t want to expose it, you can’t. This problem was solved in Java9. We can use the private modifier to limit its scope.

Such as:

public interface Metric {
    / / constant
    String NAME = "METRIC";

    // Abstract methods
    void info(a);

    // Private methods
    private void append(String tag, String info) {
        buildMetricInfo();
        System.out.println(NAME + "[" + tag + "]:" + info);
        clearMetricInfo();
    }

    // The default method
    default void appendGlobal(String message) {
        append("GLOBAL", message);
    }

    // The default method
    default void appendDetail(String message) {
        append("DETAIL", message);
    }

    // Private static methods
    private static void buildMetricInfo(a) {
        System.out.println("build base metric");
    }

    // Private static methods
    private static void clearMetricInfo(a) {
        System.out.println("clear base metric"); }}Copy the code

JShell

JShell is the REPL(Read Eval Print Loop) environment provided by the Java language. In Python, Node and other languages, with this environment for a long time, you can easily execute Java statements, quickly verify some syntax, functions, etc.

$jshellUse JShell | welcome -- version 13.0.9 | to roughly understand this version, please type: / help introCopy the code

We can view the commands directly using /help

jshell> /help| type in the Java language expressions, statement or declaration. One of | or type the following command: | / list [< name or id > | - all | - start] source | | list you type/edit > < name or id. A lot of it, for space's sake, is hiddenCopy the code

Let’s look at some simple operations:

jshell> "This is a test.".substring(5, 10);
$2 = = >"is a "

jshell>3 + 1
$3 = = > 4
Copy the code

You can also create methods:

jshell> int mulitiTen(int i) { returni*10; }| mulitiTen created method (int)
jshell>mulitiTen(3)
$6 = = > 30
Copy the code

To exit JShell, type:

jshell> /exit| byeCopy the code

JCMD added subcommands

JCMD is used to send diagnostic commands to the local JVM process. This command is a command-line tool provided from JDK7 and is often used to quickly locate online environment faults.

After JDK9, new subcommands are provided to view a list of all classes loaded in the JVM and their inheritance structures. Such as:

$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)
Copy the code

The first parameter is the process ID for which diagnostics are performed. We can also modify JVM parameters online using the set_vmflag parameter without restarting the JVM process.

Sometimes you need to check the VM options and current values for the current process: JCMD 22922 vm. flags-all.

Multiresolution image API

With the multi-resolution image API defined in Java9, we can easily manipulate and display images at different resolutions. Java awt. Image. MultiResolutionImage will a set of images with different resolution encapsulated into a single object. The java.awt.Graphics class retrieves variables from the multi-resolution image based on the currently displayed DPI metric and any applied transformations.

The following are the main operation methods of multi-resolution images:

  • Image getResolutionVariant(double destImageWidth, double destImageHeight): Gets the image variant of a specific resolution – represents a logical image of a given size with a known resolution unit of DPI, and this image is the best variant.
  • List<Image> getResolutionVariants(): Returns a list of image variants at a readable resolution.

Let’s take a look at the application:

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 images
final MultiResolutionImage multiResolutionImage = new BaseMultiResolutionImage(images.toArray(new Image[0]));

// Get all the resolutions of the image
final List<Image> variants = multiResolutionImage.getResolutionVariants();

System.out.println("Total number of images: " + variants.size());

for (Image img : variants) {
    System.out.println(img);
}

// Get 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));
Copy the code

Variable Handles

Variable Handles (Variable Handles) API is mainly used to replace Java. Util. Concurrent. The atomic package and sun. Misc. Unsafe class features, and provides a series of standard operation, the memory barrier for more granular control memory. A variable handle is a type reference to a variable (any field, array element, static table, etc.). It supports access to these types of variables under different access models, including simple read/write access, volatile read/write access, and volatile read/write access. And CAS (compare – and – swap), etc.

This section covers reflection, inline, concurrency, etc. It will be introduced separately later, and the article will be published in the journey of Java progression from child to expert, so stay tuned.

Publish – subscribe framework

Increase in Java9 Java. Util. Concurrent. The Flow support responsive API publish-and-subscribe framework, they provide a run on the JVM interoperability between many of the asynchronous system. We can customize the components with SubmissionPublisher.

For more information on responsive apis, check out www.reactive-streams.org/ and follow separately… Stay tuned on your journey to Java as an expert. How feel give oneself plane so many pit, must seize the time to fill pit.

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 functionality is specified by the -xlog startup parameter, and many tags are defined to define different types of logs, such as gc, Compiler, Threads, and so on. For example, we define debug level GC logs, which are stored in the gc.log file:

java -Xlog:gc=debug:file=gc.log:none
Copy the code

Because of the large number of parameters, we can see the specific parameters defined by java-xlog :help. And the log configuration can be changed dynamically with the JCMD command. For example, we change the log output file to gc_other.log:

jcmd ${PID} VM.log output=gc_other.log what=gc
Copy the code

The new API

Immutable set

The java.util.list.of (), java.util.set.of (), and java.util.map.of () methods added to Java9 allow you to create immutable collections in one line of code. Prior to Java9, we wanted to initialize a collection of specified values by performing a bunch of add or put methods or relying on the guava framework.

Moreover, these collection objects are mutable, and if we pass values into a method, there is no way to control that the values of these collections will not be modified. After Java9, we can initialize ImmutableCollections with initialized values with the help of definitions in ImmutableCollections. If these objects to modify (add elements, remove elements), will throw an UnsupportedOperationException anomalies.

It should be noted that Java developers also consider performance and provide different implementation classes for different numbers of collections:

  • List12,Set12,Map1Specifically for scenarios with a small number of elements (2 for List and Set, 1 pair for Map)
  • ListN,SetN,MapNApplies to scenarios with a large amount of data (more than two lists and sets, and more than one pair for maps)

Improved Optional class

Java9 added three utility methods for Optional: stream, ifPresentOrElse, and or.

Stream converts the Optional to a stream. If the Optional contains a value, the stream containing the value is returned, otherwise stream.empty () is returned. For example, we have a collection that needs to filter non-empty data. Prior to Java9, it was written as follows:

final List<Optional<String>> list = Arrays.asList(
        Optional.empty(),
        Optional.of("Mountain"),
        Optional.empty(),
        Optional.of("Cottage with a view of the mountain."));

final List<String> filteredList = list.stream()
        .flatMap(o -> o.isPresent() ? Stream.of(o.get()) : Stream.empty())
        .collect(Collectors.toList());
Copy the code

After Java9, we can use the stream method:

final List<String> filteredListJava9 = list.stream()
        .flatMap(Optional::stream)
        .collect(Collectors.toList());
Copy the code

IfPresentOrElse: If an Optional value is included, the function action (action.accept(value)) is called on the value, which is the same as ifPresent; If Optional does not contain a value, it calls emptyAction, which is emptyAction.run(). The effect is 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 is:
// Author: Look at the mountains
/ / anonymous
Copy the code

Or: Returns Optional if the value exists, otherwise returns a default value. The effect is as follows:

Optional<String> optional1 = Optional.of("Mountain");
Supplier<Optional<String>> supplierString = () -> Optional.of("Anonymous");
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 is:
// Author: Look at the mountains
// Author: Anonymous
Copy the code

At the end of the article to summarize

Java9 new features has been introduced in this paper, a complete list of features can be from openjdk.java.net/projects/jd… The new feature series for Java8 through Java17 will be complemented by a series of columns on the journey to Java from a journeyman to an expert. Green hills never change, green waters always flow. See you next time.

Recommended reading

  • This article describes 24 operations for Java8 Stream Collectors
  • Java8 Optional 6 kinds of operations
  • Use Lambda expressions to achieve super sorting functions
  • Java8 Time Library (1) : Describes the time class and common apis in Java8
  • Java8 time library (2) : Convert Date to LocalDate or LocalDateTime
  • Java8 Time Library (3) : Start using Java8 time classes
  • Java8 time library (4) : check if the date string is valid
  • New features in Java8
  • New features in Java9
  • New features in Java10
  • Optimization of access control based on nested relationships in Java11
  • New features for Java11
  • New features in Java12

Hello, I’m looking at the mountains. Swim in the code, play to enjoy life. If this article is helpful to you, please like, bookmark, follow.