Road to REPL (?) Creation (3)

Introduction

REPL made with Java8, it is the third. Since the previous article weighed more than expected, this time we will create a lighter object.

Finalizable interface

After using Java for the first time in a while, the first thing that surprised me was the lack of destructors. When I want to implement so-called ** RAII (resource acquisition is initialization) **, how do I implement it without a destructor? have become. Therefore, this time, we will create a class to realize resource acquisition / release, which will be used in REPL and others.

How to implement RAII in Java

I'm not very familiar with how to implement resource release in Java, so I'll summarize it roughly.

Object.finalize () Deprecated

Object.finalize()By overriding the method, you can write arbitrary release processing at the time of garbage collection.


 However, the finalize () method is executed when the object is destroyed by the garbage collector, so I don't know when it will be executed. Especially in the current PC environment where memory is abundant, it may not be called until the application is closed.
 For resources that can only be used in an application and can only be reused after release processing (I couldn't think of an example), there is no guarantee that the release process will work before reuse, use this method. can not.

 AutoCloseable.close()
 By creating an AutoCloseable interface implementation class and using the try-with-resource block, the implemented close () method is automatically called at the end of the try block.
 This format is generally recommended, but it must be used in a single method, so it cannot be used, for example, if you want to destroy a composition object when you want to destroy the parent object. There is also a way to call close () of the composition object by yourself, but is it the original usage? I doubt if asked.


#### **`python`**
```java

try ( InputStreamReader in = new InputStreamReader(filepath) ) {
    char c = in.read();  //Processing using in
    method(in);   //It is OK to pass in via the method on the way
    // ..Other processing
}   //Where in is automatically released

Finalizer (the one I will explain this time)

Therefore, we will implement the Finalizer class that releases the registered objects.

Finalizable interface

It is an interface to be implemented in the class that wants to perform termination processing. It is a mechanism to make Finlizer keep the collection of Finalizable and call cleanup () of the objects in the collection sequentially at the end.

Interface.java


package console;

interface Interface {
    interface Finalizable {
        void cleanup();
    }
}

Finalizer class

This is the container of the Finalizable implementation class and the termination processing contract class.

python


package console;

final class Finalizer {
    /**Finalizable implementation class registration. */
    final void  register(Interface.Finalizable f) {
        if ( finalizers_.contains(f) ) { return; }
        finalizers_.add(0, f);  // push front
    }

    final void remove(Interface.Finalizable f) {
        if ( !finalizers_.contains(f) ) { return; }
        finalizers_.remove(f);
    }

    /**Registered Finalizable.cleanup()To call and delete in the reverse order of registration. */
    final void cleanup() {
        for ( Interface.Finalizable f: finalizers_ ) {
            try {
                f.cleanup();
            } catch(java.lang.RuntimeException e) {
                System.err.println( e.getMessage() );
            }
        }
        finalizers_.clear();
        finalizers_ = null;
    }

    private java.util.List<Interface.Finalizable> finalizers_ = new java.util.ArrayList<>();
}

Example of registration of dependent objects

If you want to release resources and Hoge is required to initialize Foo, register it in Finlaizer in the order of Hoge → Foo. By doing this, Hoge will not be released before Foo, so even if you use Foo in Hoge.cleanup (), there will be no problem. However, unless you manually call Foo.cleanup () ...

【Example of use】


    Finalizer fin = new Finalizer();
    Hoge h = new Hoge();
    fin.register(h);
    Foo  f = new Foo(h);
    fin.register(f);
 
    // ... Hoge,Processing using Foo

    fin.cleanup()

Summary

Finalizer.cleanup () needs to be called by itself when destroying an object, but if you register it here, resources will be released at once, so if you implement it properly, you can solve the concern of resource leakage considerably. think. The cleanup () method with the same name as the method in the Finalizer class is registered as an abstract class in Part 1 of the BaseREPL class. When using Finalizer in the derived class, if you call Finalizer.cleanup () method from this method, you can surely execute the resource release process registered just before the end of BaseREPL.run () method. I will.

Implementation example in REPL


class XxxxREPL extends BaseREPL {
    XxxxREPL(String encoding) {
        super(encoding);
        obj1 = new Object1();
        finalizer.register(obj1);
        finalizer.register(obj2);
    }

    protected void cleanup() {
        finalizer.cleanup(): //cleanup in the order of obj2, obj1()Is called
    }

    private Finalizer finalizer = new Finalizer();
    private Object1 /* implements Finalizable */  obj1;
    private Object2 /* implements Finalizable */  obj2 = new Object2();
}

Recommended Posts

Road to REPL (?) Creation (3)
Road to REPL (?) Creation (1)
Road to REPL (?) Creation (2)
19 Corresponds to object creation
Road to Java SE 11 Silver acquisition
Y-shaped road tour (how to write)
The road from JavaScript to Java
[Docker] Operation up to container creation # 2
to_ ○
The road to creating a music game 2
Java SE8 Silver ~ The Road to Pass ~
Introduction to kotlin for iOS developers ⑥-Kotlin creation
The road to creating a music game 3
The road to creating a music game 1