Core Java

New Features in Java 9

Java 9, released in 2017, introduced several noteworthy features. Let us delve into the new Java 9 features.

1. Modular System – Jigsaw Project

The Modular System, also known as Project Jigsaw, is a significant feature introduced in Java 9 to enhance the modularity of the Java platform. Project Jigsaw aims to address the long-standing issue of managing and organizing large-scale Java applications. It introduces a module system that allows developers to create modularized code, improving maintainability, scalability, and encapsulation. Key components of the Modular System include:

  • Module Declarations: Developers define modules using the module-info.java file, specifying dependencies and providing a clear API.
  • Encapsulation: Modules encapsulate their internal implementation, exposing only selected parts through a well-defined interface. This enhances security and reduces accidental dependencies.
  • Improved Scalability: Large applications can be divided into smaller, manageable modules, promoting better organization and understanding of codebases.
  • Dependency Resolution: The module system facilitates explicit dependencies between modules, resolving them at compile time and runtime, leading to more reliable and efficient applications.

2. New HTTP Client

Java 9 introduces a modern and flexible HTTP Client API that brings several enhancements over the traditional HttpURLConnection. Key features of the new HTTP Client include:

  • Asynchronous Support: The new HTTP Client supports asynchronous operations, allowing developers to perform non-blocking requests.
  • WebSocket: Java 9 HTTP Client provides native support for WebSocket communication, simplifying the development of real-time applications.
  • Response Body Handling: Easily handle response bodies using new methods, providing more control and flexibility.
  • Request Building: Constructing HTTP requests is more intuitive with the fluent API, making it simpler to customize requests.

Here’s a simple example demonstrating the usage of the new HTTP Client in Java 9.

import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;

public class NewHttpClientExample {
	public static void main(String[] args) throws Exception {
		HttpClient client = HttpClient.newHttpClient();
		HttpRequest request = HttpRequest.newBuilder()
				.uri(new URI("https://example.com"))
				.build();

		HttpResponse response = client.send(request, HttpResponse.BodyHandlers.ofString());
		System.out.println("Response Code: " + response.statusCode());
		System.out.println("Response Body: " + response.body());
	}
}

3. Process API

Explore the enhancements to the Process API in Java 9, providing improved control over operating system processes. Key features of the Process API include:

  • Process Handles: Java 9 introduces the concept of Process Handles, providing a more comprehensive and flexible way to interact with native processes.
  • Control over Process Lifecycle: Developers can now perform operations such as start, stop, and inspect processes with greater ease and precision.
  • Access to PID (Process ID): The Process API in Java 9 enables retrieval of the Process ID, offering better visibility and control over processes.
  • Improved Stream Handling: Java 9 enhances the handling of process input and output streams, simplifying communication with external processes.

Here’s a simple example demonstrating the usage of the Process API in Java 9 to execute an external process.

import java.io.IOException;
import java.util.List;

public class ProcessApiExample {
	public static void main(String[] args) throws IOException, InterruptedException {
		ProcessBuilder processBuilder = new ProcessBuilder("echo", "Hello, Java 9 Process API!");
		Process process = processBuilder.start();
		int exitCode = process.waitFor();
		System.out.println("Process exited with code: " + exitCode);
	}
}

4. Small Language Modifications

Java 9 brought several small but impactful language modifications to enhance developer productivity and code readability.

4.1 Diamond Operator Enhancement

The diamond operator, introduced in Java 7, is now more versatile in Java 9. It can be used with anonymous classes, making code cleaner and more concise:

List<String> names = new ArrayList<>() {
// Anonymous class implementation
};

4.2 Try-With-Resources Improvement

Java 9 allows the effective use of the try-with-resources statement with resources that are already effectively final or effectively immutable. This eliminates the need for an explicit final modifier in many cases:

InputStream inputStream = new FileInputStream("example.txt");

try (inputStream) {
  // Code that uses inputStream
} catch (IOException e) {
  // Exception handling
}

4.3 Private Methods in Interfaces

Interfaces can now have private methods, enabling code reuse among default or static methods within the interface:

public interface MyInterface {
  default void publicMethod() {
    // Public method implementation
    privateMethod();
  }

  private void privateMethod() {
    // Private method implementation
  }
}

4.4 Module System

Java 9 introduced the module system, allowing developers to create modular and scalable applications. This helps in better organizing code and managing dependencies:

module com.example.myapp {
  requires module1;
  requires module2;
  exports com.example.myapp;
}

5. JShell Command Line Tool

Java 9 introduced a revolutionary feature for developers known as JShell – a Read-Eval-Print Loop (REPL) that allows for interactive and immediate execution of Java code snippets.

5.1 Getting Started with JShell

JShell provides a simple and interactive interface where developers can type Java code and see immediate results. JShell provides various commands and features to enhance your interactive experience, such as:

  • /help: Display a list of available commands.
  • /vars: List all declared variables.
  • /methods: List all defined methods.
  • /edit: Open the last input for editing in the default text editor.

To start JShell, simply open a command prompt or terminal and type:

jshell

This opens the JShell environment, ready for you to start entering Java expressions and statements. One of the key advantages of JShell is the immediate feedback it provides. As you type each line of code, JShell evaluates and executes it on the fly, giving you instant results. This facilitates experimentation and learning without the need to compile and run a complete Java program.

5.2 Variables and Expressions

JShell allows you to declare variables and evaluate expressions interactively. For example:

int x = 5;
int y = 10;

x + y

The result of the last expression (x + y) is immediately displayed by JShell.

5.3 Multi-Line Input

JShell supports multi-line input, making it convenient for writing more complex code snippets. You can use the slash (/) at the end of a line to indicate that the code continues on the next line:

String message = "Hello, " +
  "World!";
System.out.println(message);

6. JCMD Sub-Commands

Java Command (JCMD) is a command-line utility introduced in Java that allows you to interact with Java Virtual Machines to monitor and manage Java applications.

6.1 List Available Processes

Use the following command to list all available Java processes running on the machine:

jcmd

This command displays a list of Java processes along with their process IDs (PIDs).

6.2 VM System Properties

Retrieve and display system properties from a running Java process using the following syntax:

jcmd <PID> VM.system_properties

This command provides valuable information about the system properties of the Java process.

6.3 Thread Stack Traces

Obtain thread stack traces from a Java process to diagnose performance or debugging issues:

jcmd <PID> Thread.print

This command prints the stack traces of all threads in the specified Java process.

6.4 GC-related Operations

Perform garbage collection-related operations, such as obtaining garbage collection statistics:

jcmd <PID> GC.class_histogram

This command displays a histogram of the current heap usage by class.

6.5 Java Flight Recorder (JFR)

Start and stop Java Flight Recorder recordings for performance analysis:

jcmd <PID> JFR.start

jcmd <PID> JFR.stop filename=myrecording.jfr

These commands initiate and stop a Java Flight Recorder recording, saving the data to the specified file.

7. Мulti-Resolution Image API

Java introduced the Multi-Resolution Image API as part of Java SE 9 to simplify the handling of images at different resolutions. This API is particularly useful for developing applications that run on devices with varying screen densities or for providing better user experiences across different platforms.

7.1 Creating Multi-Resolution Images

To create a multi-resolution image, you can use the MultiResolutionImage class. This class takes a list of images at different resolutions as its constructor parameter:

List<Image> resolutionVariants = List.of(
  new Image("image-1x.png"),
  new Image("image-2x.png"),
  new Image("image-4x.png")
);

MultiResolutionImage multiResImage = new MultiResolutionImage(resolutionVariants);

7.2 Retrieving the Best Image

Once you have a MultiResolutionImage instance, you can obtain the most suitable image for a given size using the getResolutionVariant method:

Image bestImage = multiResImage.getResolutionVariant(100, 100);

This returns the image variant that best matches the provided width and height.

7.3 Working with Platform-Dependent Variants

The API also allows you to provide platform-dependent variants. For example, you can specify different images for Windows, macOS, and Linux:

Map<String, Image> platformVariants = Map.of(
  "win", new Image("image-win.png"),
  "mac", new Image("image-mac.png"),
  "linux", new Image("image-linux.png"));

MultiResolutionImage platformImage = new MultiResolutionImage(platformVariants);

8. Variable Handles

Java 9 introduced a new feature known as Variable Handles, which provides a flexible and efficient way to access and manipulate variables, particularly in a concurrent environment. Variable Handles are valuable in scenarios where fine-grained control over variable access and manipulation is required, especially in concurrent programming. They offer improved performance compared to traditional synchronization mechanisms, making them suitable for high-performance applications.

8.1 Creating Variable Handles

Variable Handles can be created for fields using the VarHandle class. The following example demonstrates how to create a Variable Handle for an integer field:

VarHandle intHandle = MethodHandles.lookup()
  .in(MyClass.class)
  .findVarHandle(MyClass.class, "myField", int.class);

This creates a Variable Handle for the myField integer field in the MyClass class.

8.2 Atomic Operations with Variable Handles

Variable Handles provide atomic operations, allowing safe manipulation of variables in a concurrent environment. The example below demonstrates an atomic addition operation:

intHandle.getAndAdd(myInstance, 5);

This atomically adds 5 to the value of the “myField” variable in the specified instance of “MyClass.”

8.3 Memory Ordering and Volatile Variables

Variable Handles provide control over memory ordering, especially important for volatile variables in concurrent programming. The following example demonstrates creating a Variable Handle for a volatile boolean field:

VarHandle booleanHandle = MethodHandles.lookup()
  .findVarHandle(MyClass.class, "myVolatileField", boolean.class);

9. Publish-Subscribe Framework

A Publish-Subscribe framework is a messaging pattern that facilitates communication between different components in a software system. This pattern is widely used to build scalable and loosely coupled architectures, allowing components to communicate without being directly aware of each other. The key components of a Publish-Subscribe framework include:

  • Publisher: The entity responsible for producing and broadcasting messages.
  • Subscriber: The entity that expresses interest in specific types of messages and receives them when published.
  • Message/Event: The information or notification published by the publisher and consumed by subscribers.
  • Broker/Hub: The central component that manages the communication between publishers and subscribers, ensuring proper message delivery.

9.1 Benefits

The Publish-Subscribe pattern offers several advantages, including:

  • Decoupling: Publishers and subscribers are decoupled, allowing changes in one component without affecting the others.
  • Scalability: Easily scale the number of publishers and subscribers without tight dependencies.
  • Flexibility: New components can be added without modifying existing ones, promoting flexibility in system design.
  • Asynchronicity: Supports asynchronous communication, enabling efficient handling of large numbers of messages.

9.2 Use Cases

The Publish-Subscribe pattern is applicable in various scenarios, including:

  • Event-driven architectures
  • Real-time data processing
  • Notification systems
  • Distributed systems

10. Unified JVM Logging

Unified JVM Logging, introduced in Java 9, is a comprehensive logging framework that aims to improve the consistency and efficiency of logging across different components of the Java Virtual Machine (JVM). Before Java 9, each component of the JVM had its logging system, leading to inconsistencies and making it challenging for developers to manage and analyze logs effectively.

The Unified JVM Logging framework addresses this issue by providing a single, standardized logging system for all components of the JVM. It leverages the java.util.logging package and introduces a common logging configuration file, enabling developers to configure logging properties consistently across the entire JVM.

One of the key benefits of Unified JVM Logging is its simplicity and ease of use. Developers can configure logging settings through the logging.properties file, allowing them to control log levels, output formats, and destinations such as files or the console. This uniform configuration simplifies the process of troubleshooting and debugging, as developers no longer need to navigate through different logging configurations for various JVM components.

Unified JVM Logging also introduces a new command-line option, -Xlog, which provides a flexible and expressive syntax for configuring logging at runtime. This option allows developers to enable or disable specific log tags, set log levels, and direct log output to different destinations dynamically. The ability to adjust logging settings on the fly greatly facilitates troubleshooting in production environments without requiring a JVM restart.

With Unified JVM Logging, developers can now rely on a consistent and streamlined approach to logging throughout the JVM. Whether dealing with classloading, garbage collection, or application-specific components, the unified framework simplifies the process of gathering and analyzing logs, leading to improved maintenance, debugging, and overall system reliability.

11. New APIs

Java 9 brought several exciting additions to its API library, enhancing the language’s capabilities and providing developers with powerful tools for various tasks.

  • Process API: Java 9 introduced an enhanced Process API, making it easier to interact with native processes. The new ProcessHandle class allows developers to obtain information about, control, and monitor native processes. This API simplifies tasks such as retrieving the process ID, checking the process’s existence, and performing other management operations.
  • Reactive Streams API: The Reactive Streams API in Java 9 provides a standard for asynchronous stream processing with non-blocking backpressure. This API is defined in the java.util.concurrent.Flow package facilitates the development of reactive applications by allowing publishers to signal subscribers about the amount of data they can handle, preventing overflow situations.
  • HTTP/2 Client: Java 9 introduced a new HTTP/2 client API in the java.net.http package. This API simplifies the development of HTTP clients and supports HTTP/2, WebSocket, and asynchronous programming. The HTTP/2 client offers a more modern and efficient alternative to the legacy HttpURLConnection class.
  • Optional API Enhancements: Java 9 enhanced the Optional class with additional methods to make it more versatile. New methods like ifPresentOrElse, stream, and or provide developers with more expressive ways to handle optional values, improving code readability and conciseness.
  • VarHandle API: The VarHandle API introduced in Java 9 provides a flexible and efficient way to access and manipulate variables, particularly in a concurrent environment. This API offers atomic operations and support for volatile variables, making it a powerful tool for low-level variable access and manipulation.

12. Conclusion

In conclusion, Java 9 brought a significant evolution to the language with a myriad of features and improvements. The introduction of the Modular System through the Jigsaw Project addressed long-standing issues related to modularity, enabling developers to create more maintainable and scalable applications. The addition of a new HTTP client streamlined communication, while the Process API simplified interaction with native processes. Small language modifications improved code readability and conciseness, contributing to a more developer-friendly experience. The JShell Command Line Tool introduced an interactive and immediate way to experiment with Java code snippets. JCMD sub-commands facilitated better management of Java processes. The Multi-Resolution Image API allowed for handling images at different resolutions seamlessly. Variable Handles provided a powerful and efficient way to access and manipulate variables, particularly in concurrent environments. The Publish-Subscribe Framework enhanced communication between components, fostering scalable and loosely coupled architectures. Unified JVM Logging standardized logging across the JVM components. Finally, the introduction of new APIs enriched the Java ecosystem, offering developers powerful tools to tackle diverse programming challenges. Overall, Java 9 marked a pivotal moment in the language’s evolution, ushering in modern features and improvements that continue to shape the landscape of Java development.

Yatin

An experience full-stack engineer well versed with Core Java, Spring/Springboot, MVC, Security, AOP, Frontend (Angular & React), and cloud technologies (such as AWS, GCP, Jenkins, Docker, K8).
Subscribe
Notify of
guest

This site uses Akismet to reduce spam. Learn how your comment data is processed.

0 Comments
Inline Feedbacks
View all comments
Back to top button