4

So i have been going through "Effective Java 2nd Ed."

In item 7 he talks about not using finalizers because they can cause a lot of problems .

But instead of using finalizers we can " provide an explicit termination method" and an example of those is the close statement . and i did not understand what is " termination statements and what are the differences between them and finalizers ?

I came to the conclusion that terminating an object is like nulling it thus the resourses is released . but i think i don`t understand the difference that well . so i appreciate any help .

Thanks !

titorat
  • 83
  • 8
  • 2
    nullifying an object doesn't release anything. – assylias Jun 05 '17 at 14:12
  • 2
    I think you skipped over the part that explains that finalizers are used for cleaning up things which are not memory (e.g. open connections, open files, other system resources). You need to do these things otherwise you'll have a resource leak. – RealSkeptic Jun 05 '17 at 14:14

2 Answers2

8

But instead of using finalizers we can " provide an explicit termination method" and an example of those is the close statement .

The authors refers to a close() method that provides a way to clean an object that uses resources to free.

For example when you create and manipulate an InputStream or an OutputStream, you don't want to rely on Java finalizers (that may exist for some subclasses of these interface. For example it is the case for the FileInputStream class that defines a finalize() method) to release the resources associated to the stream but you want to use the method provided by the API to do it : void close() as it is more reliable as finalizer.

java.sql.Statement works in the same way : it provides a close() method to release JDBC resources associated to the statement instance.

I came to the conclusion that terminating an object is like nulling it thus the resourses is released .

Assigning an object to null will not necessary free all resources that should be freed. Besides if the object or a field of the object is still referenced by another living object, the object would be not illegible to be garbage collected

At last, being garbage collected may also take a some time.
Why wait if we don't need to use the object ?

davidxxx
  • 125,838
  • 23
  • 214
  • 215
  • Thanks for the explanation! But I still don't exactly understand what is the difference between close and finalize? And what exactly close method do to clean the object? I know that finalize is the garbage collection method which clean objects. But what exactly the close method does that finalize method do or don't do?! – titorat Jun 05 '17 at 15:01
  • You are welcome.`close()` and finalizer have the same intention and do the same thing : clean and free resources that are not required any longer for an object. "I know that finalize is the garbage collection method which clean objects" Yes but to clean the object you have to override the `finalize()` method in your class. If you don't override it, the method does nothing. Read the javadoc associated to : **The finalize method of class Object performs no special action; it simply returns normally**. – davidxxx Jun 05 '17 at 15:11
  • The difference between the two methods is `finalize()` may be never called or called very late (so some resources may not be freed before a some delay) while if the client code calls explicitly a `close()` method (documented as a method to free resources associated to the object) on the object, you are sure to free the resources as soon as the invocation of `close()` is returned. – davidxxx Jun 05 '17 at 15:12
  • Okay now I somehow understand the difference. So if I am making an API and I want the client to be able to terminate an object with explicitly terminating method how could I declare a close method in the API that I am making? Please if this not even a valid question just tell me this because I am still a beginner. Thanks anyway for your informative answer and comments! – titorat Jun 05 '17 at 15:35
  • Don't worry : it is a very valid question. How to declare a public `close()` method ? You have just to add it in your class/interface and specify in the javadoc of this method what the method does. Generally an API provided to client classes should rely on interfaces. So you should define `close()` in the interface first and implement it in the implementation class. I am glad if these may have helped you. – davidxxx Jun 05 '17 at 15:43
  • Sorry I meant the implementation not the declaration. I mean how should it be implemented? I feel like I am missing something here. So implementing a close method in a class might be by freeing resources? Is the object terminated by freeing resource or what? – titorat Jun 05 '17 at 15:49
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/145898/discussion-between-davidxxx-and-titorat). – davidxxx Jun 05 '17 at 15:49
1

The main difference between an explicit termination method and finalize() is that the second one is not guaranteed to be called. It's called eventually during garbage collection which might to be honest never occur. Lets consider the following three classes.

class Foo {
    @Override
    public void finalize() {
        System.out.println("Finalize Foo");
    }
}

class Bar implements Closeable {
    @Override
    public void close() {
        System.out.println("Close Bar");
    }
}

class Baz implements AutoCloseable {
    @Override
    public void close() {
        System.out.println("Close Baz");
    }
}

The first one overrides the finalize() method inherited from Object. Foo and Bar implement both interfaces which are handled by ARM (Automatic Resource Management).

Foo foo = new Foo();
new Foo();
try (Bar bar = new Bar(); Baz baz = new Baz()) { // this is ARM 
    System.out.println("termination example");
}
Bar bar = null;
try {
    bar = new Bar();
    // ...
} finally {
    if (bar != null) {
        bar.close();
    }
}

This example should return:

termination example
Close Baz
Close Bar
Close Bar

The finalize() method of Foo gets never called because Foo is not garbage collected. The JVM has available resources, so for performance optimization it does not perform garbage collecting. Furthermore - if a resource isn't garbage collected despite the fact of finishing the Application. Even the second created instance of Foo is not Garbage Collected, because there is plenty of resources for the JVM to thrive.

The second one with ARM is a lot better, because it creates both the resources (one implementing java.io.Closeable and one implementing java.lang.AutoCloseable, it's worth mentioning that Closeable extends AutoCloseable, that's why it's available for ARM). ARM guaranties for both of these resources to be closed, to close one when the other throws and so on. The second one presents something similar to ARM, but saving a lot of unnecessary boilerplate code.

Something making you a better developer:

But it's still not perfect. There is still a burden on the programmer to remember closing the object. The absence of destructors in Java forces the developer either to remember closing the resource, remember to use ARM and so on. There is a good design pattern (good explained by Venkat Subramaniam) - the Loan Pattern. A simple example of the loan pattern:

class Loan {
    private Loan() {
    }

    public Loan doSomething(int m) {
        System.out.println("Did something " + m);
        if (new Random().nextBoolean()) {
            throw new RuntimeException("Didn't see that commming");
        }
        return this;
    }

    public Loan doOtherThing(int n) {
        System.out.println("Did other thing " + n);
        return this;
    }

    private void close() {
        System.out.println("Closed");
    }

    public static void loan(Consumer<Loan> toPerform) {
        Loan loan = new Loan();
        try {
            toPerform.accept(loan);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            loan.close();
        }
    }
}

You can use it like that:

class Main {
    public static void main(String[] args) {
        Loan.loan(loan -> loan.doOtherThing(2)
                .doSomething(3)
                .doOtherThing(3));
    }
}

It relieves the developer of the burden of closing the resource, because it has already been handled for him. If one of these methods throws, then it's handled and the developer does not have to bother. The close method and constructor are private to not tempt the developer to use them.

Adrian Jałoszewski
  • 1,695
  • 3
  • 17
  • 33