Extremely Serious

Category: Java 9

Java Cleaner

Java Cleaner is a new feature introduced in Java 9 that allows you to define cleanup actions for groups of objects. Cleaners are implemented with the Cleanable interface, which descends from Runnable. Each Cleanable represents an object and a cleaning action registered in a Cleaner. Each Cleanable runs in a dedicated thread. All exceptions thrown by the cleaning action are ignored.

Java 18, marked the finalize method for removal. It is better to avoid the usage of finalize method.

The most efficient use of Cleaner is to explicitly invoke the clean() method when the object is closed or no longer needed. Note that the cleaning action must not refer to the object being registered.

Cleaners provide a more reliable way to perform cleanup tasks than relying on finalization. Finalization is often unreliable because it is not guaranteed to be called before the object is garbage collected. Cleaners, on the other hand, are guaranteed to be called before the object is garbage collected, as long as the clean() method is invoked.

See the sample usage of a Java Cleaner below:

import java.lang.ref.Cleaner;

public class SampleResourceUsage implements AutoCloseable {

    /**
     * A cleaner, preferably one shared within a library
     */
    private static final Cleaner cleaner = Cleaner.create();

    /**
     * An instance of Cleaner.Cleanable that the register returned.
     */
    final private Cleaner.Cleanable cleanable;

    /**
     * The resource that should be cleaned after use.
     */
    final private CloseableResource resource;

    public SampleResourceUsage() {
        //Instantiate a resource that must be cleaned after use.
        resource = new CloseableResource();

        //Register with the cleaner.
        cleanable = cleaner.register(this, resource::close);
    }

    public void use() {
        resource.use();
    }

    @Override
    public void close() {
        //Use clean method from the Cleanable instance to close the resource.
        cleanable.clean();
    }

    public static void main(String ... args) throws InterruptedException {
        //Create an instance with cleanable resource.
        var resource = new SampleResourceUsage();
        resource.use();

        //Remove the instance reference.
        resource = null;

        //Request for a garbage collection.
        System.gc();

        //Try to wait for a garbage collection to complete.
        //If garbage collection was not triggered. Increase the timeout.
        Thread.sleep(1000);
    }

    /**
     * The class that should have clean up operation.
     */
    private static class CloseableResource {
        public void use() {
            System.out.println("Using the resource that must be cleaned.");
        }

        /**
         * The cleaner that must be called for garbage collection.
         */
        public void close() {
            System.out.println("Cleaning up.");
        }
    }
}

Expect to see the following output:

Using the resource.
Cleaning up.

If you didn't see preceding output, you might need to check the timeout value.

Here are some additional things to keep in mind when using Java Cleaner:

  • The Cleaner object is a heavyweight object, so it should be shared whenever possible.
  • The Cleaner thread is a daemon thread, so it will not prevent your program from exiting.
  • The clean() method can only be called once. If you need to perform multiple cleanup actions, you should use a Runnable object to wrap the cleanup actions.

Module-Info Syntax

[open] module <MODULE_NAME> {
    [[requires [transitive] <MODULE_NAME>;]
    [exports <PACKAGE>[ to <MODULE_NAME_1>[,<MODULE_NAME_2>..,<MODULE_NAME_N>];]
    [opens <PACKAGE>;]
    [provides <SERVICE> with <SERVICE_IMPLEMENTATION_1>[,<SERVICE_IMPLEMENTATION_2>..,<SERVICE_IMPLEMENTATION_N>];]
    [uses <SERVICE>;]]
}
Identifier Description
module The module keyword that holds the module directives.
<MODULE_NAME> The module identier.
<PACKAGE> The package identifier.
requires The requires directive indicates that this module depends on another module. ^1
transitive The transitive directive indicates that the user of the current module will also requite another module that the current user will also have access into.
exports The exports directive indicates which public types of the module's package are accessible to other modules. ^1
opens The opens directive also indicates which public types of the module's package are accessible to other modules. The difference between that and exports is that opens is not for compile time, only during runtime, while exports is for both compile time and runtime. The opens directive can typically be used when you want to allow other modules to use reflection for the types in the specified packages, but not to use them during compile time. Let's make this more clear by means of an example. ^1
open This is like the opens directive but with this it opens the whole module.
to <MODULE_NAME_1>[, <MODULE_NAME_2>.., <MODULE_NAME_N>] This indicates to target just specific module(s).
provides...with The provides...with directive indicates that the module provides a service implementation.^1
uses The uses directive indicates that the module requires a service implementation.
<SERVICE> The interface or abstract class that will be implemented as a service.
<SERVICE_IMPLEMENTATION_1>[, <SERVICE_IMPLEMENTATION_2>.., <SERVICE_IMPLEMENTATION_N>] The implementation classes of the SERVICE_INTERFACE.

Using Embedded Derby in Java 9 with Gradle

  1. Add the following dependencies to your build.gradle file:
    compile group: 'org.apache.derby', name: 'derby', version: '10.15.1.3'
    compile group: 'org.apache.derby', name: 'derbyshared', version: '10.15.1.3'
  2. Add the following entries to your module-info.java file:
    requires org.apache.derby.engine;
    requires org.apache.derby.commons;
    requires java.sql;
    
  3. In your Java class, you can create a connection like the following:
    final String DATABASE_NAME = "sample_table";
    String connectionURL = String.format("jdbc:derby:%s;create=true", DATABASE_NAME);
    connection = DriverManager.getConnection(connectionURL);
    
  4. Do your needed database operations with the connection (e.g. create table, execute a query, or call a stored procedure.).
  5. When your done using the connection, close the connection and shutdown the Derby engine like the following:
    connection.close();
    
    boolean gotSQLExc = false;
    try {
        //shutdown all databases and the Derby engine
        DriverManager.getConnection("jdbc:derby:;shutdown=true");
    } catch (SQLException se)  {
        if ( se.getSQLState().equals("XJ015") ) {
            gotSQLExc = true;
        }
    }
    if (!gotSQLExc) {
        System.out.println("Database did not shut down normally");
    }

    A clean shutdown always throws SQL exception XJ015, which can be ignored.

Getting a Resource using ModuleLayer

If the resource and the module are known, we can use the ModuleLayer to access it like the following snippet.

ModuleLayer.boot().findModule(<MODULE_NAME>).ifPresent(___module -> {
    try {
        var modResource = ___module.getResourceAsStream(<RESOURCE_NAME>);
    } catch (IOException e) {
        e.printStackTrace();
    }
});

Where:

MODULE_NAME -> the name of the module that has the resource.
RESOURCE_NAME -> the resource of interest.

Sample Usage of Java 9 Flow (Reactive Stream) API

Reactive stream is gaining traction in the mainstream programming and java has its own implementation via the Flow API. Popular reactive stream implementations are RxJava, Reactor and Akka.

import java.util.concurrent.Flow;
import java.util.concurrent.SubmissionPublisher;
import java.util.stream.IntStream;

public class Main {

    /**
     * Sample subscriber implementation.
     */
    public static class Subscriber implements Flow.Subscriber<Integer> {

        /**
         * Holds an instance of Flow.Subscription instance so that we can request what we can handle.
         */
        private Flow.Subscription subscription;

        /**
         * Tracks if the publisher was closed.
         */
        private boolean isDone;

        /**
         * Triggered on the initial subscription.
         * @param subscription An instance of Flow.Subscription.
         */
        @Override
        public void onSubscribe(Flow.Subscription subscription) {
            System.out.println("Subscribed");
            this.subscription = subscription;
            this.subscription.request(1);
        }

        /**
         * Do the actual processing.
         * @param item The actual item currently being processed.
         */
        @Override
        public void onNext(Integer item) {
            System.out.println("Processing " + item);
            this.subscription.request(1);
        }

        /**
         * Holds how to handle error.
         * @param throwable An instance of Throwable.
         */
        @Override
        public void onError(Throwable throwable) {
            throwable.printStackTrace();
        }

        /**
         * Called with the publisher was closed or completed.
         */
        @Override
        public void onComplete() {
            System.out.println("Processing done.");
            isDone = true;
        }
    }

    public static void main(String[] args) throws InterruptedException {
        
        //The publisher of the data.
        SubmissionPublisher<Integer> publisher = new SubmissionPublisher<>();

        //The sample subscriber implementation.
        Subscriber subscriber = new Subscriber();
        
        //Register a subscriber.
        publisher.subscribe(subscriber);

        //The sample stream to process.
        var intData = IntStream.rangeClosed(1, 10);

        //Publish the stream data. 
        intData.forEach(publisher::submit);

        //The publisher is done.
        publisher.close();

        //Since this is processing is asynchronous wait for everything to be processed. 
        while(!subscriber.isDone) {
            Thread.sleep(10);
        }
        
        System.out.println("Done");
    }
}

Using JShell for testing an API

Java 9 was released and JShell (i.e. The REPL of Java) is now real and we can use this to test an API.

For example if we want to check the reverse function StringUtils from the commons-lang3-3.1.jar.
1.) Using windows terminal (i.e. cmd command).
2.) From this directory execute to following command jshell command.
jshell --class-path .\commons-lang3-3.1.jar
Expect to see something similar to the following:
Welcome to JShell -- Version 9.0.1
For an introduction type: /help intro

jshell>
3.) From the jshell prompt import the class org.apache.commons.lang3.StringUtils just like we normally do in java and then press enter.
e.g.
jshell> import org.apache.commons.lang3.StringUtils
4.) To optionally check all the imported classes on the current jshell session we can use /imports command.
e.g.
jshell> /imports
The sample output would be:
|    import java.io.*
|    import java.math.*
|    import java.net.*
|    import java.nio.file.*
|    import java.util.*
|    import java.util.concurrent.*
|    import java.util.function.*
|    import java.util.prefs.*
|    import java.util.regex.*
|    import java.util.stream.*
|    import org.apache.commons.lang3.StringUtils
5.) Since we know that the StringUtils class was already loaded. We can now execute its reverse function.
e.g.
jshell> StringUtils.reverse("abcde")
The output must be:
$2 ==> "edcba"
Note: if you want to exit jshell execute the /exit command.