7

Experienced programmer new to Java seeking your wisdom:

If there is no way to ensure that some particular chunk code is executed as an object goes out of scope, then what other approaches are there that would offer the same functionality? (it seems finalize is clearly not meant for that)

A classic example is the scoped lock idiom:

void method()
{
    // Thread-unsafe operations {...}

    { // <- New scope
        // Give a mutex to the lock
        ScopedLock lock(m_mutex);

        // thread safe operations {...}

        if (...) return; // Mutex is unlocked automatically on return

        // thread safe operations {...}

    } // <- End of scope, Mutex is unlocked automatically

    // Thread-unsafe operations {...}
}

I can understand that in Java it would be frowned upon to have some code executed if you haven't explicitly called it. But I find being able to enforce some code to be executed at the end of an object's lifetime is a very powerful feature to ensure your classes are being used sensibly by client code. Thanks

  • Agree, it is powerful. I wish Java had something like C#'s `using` statement at times. +1 Edit: Guess Java does have this. see OldCurmudgeon's answer. If you don't use Java 7, I'd go with try/finally approach for errors. Though for locking there's no automatic handling. – William Morrison Aug 20 '13 at 13:42

4 Answers4

9

Generally - if you have a need to actually close/dispose of resources then using a try{} finally{} structure is encouraged.

  // The old way - using try/finally
  Statement stmt = con.createStatement();
  try {
    ResultSet rs = stmt.executeQuery(query);
    while (rs.next()) {
      // ...
    }
  } catch (SQLException e) {
    // Whatever ... .
  } finally {
    // Be sure to close the statement.
    if (stmt != null) {
      stmt.close();
    }
  }

More recent incarnations of java have the AutoCloseable interface which you can use with the with mechanism. All Closeable objects are automatically AutoCloseable.

  // Example of what is called try-with
  try (Statement stmt = con.createStatement()) {
    ResultSet rs = stmt.executeQuery(query);
    while (rs.next()) {
      // ...
    }
  } catch (SQLException e) {
    // Whatever ... stmt will be closed.
  }
OldCurmudgeon
  • 64,482
  • 16
  • 119
  • 213
  • +1, didn't know this existed. So I guess Java does have an equivalent to C#'s `using` statement now. – William Morrison Aug 20 '13 at 13:45
  • The try(resource) form seems to be the closest thing indeed. But it requires the client code to do the right thing. But what if the internal resource inside the Statement object is an implementation detail that the user should not know about? Is there a way to get close() to execute without explicit measures required by the user? – user1659313 Aug 20 '13 at 14:03
  • 1
    No, there isn't. Even the try-with-resource was debated for this non-obviousness characteristic, which goes against the spirit of Java, therefore against the seasoned Java programmer's intuition. – Marko Topolnik Aug 20 '13 at 14:08
  • Thanks Marko, that's petty much the answer I expected, and it's a somwhat sad but very valid one :) – user1659313 Aug 20 '13 at 14:11
2

As of Java 7 there is the Automatic Resource Management. If your lock is under your control, then make it implement AutoCloseable. Unfortunately, the java.util.concurrent locks do not implement this interface. Here's a good reference to the details of that.

Community
  • 1
  • 1
Marko Topolnik
  • 195,646
  • 29
  • 319
  • 436
1

Another option to replace finalize method is PhantomReference. If you want to perform some action before object is garbage colected then it offers another good approach better than finalize method.

Check for example here : https://weblogs.java.net/blog/kcpeppe/archive/2011/09/29/mysterious-phantom-reference

Lokesh
  • 7,810
  • 6
  • 48
  • 78
  • There is no guarantee that an object will be garbage collected. – jontro Aug 20 '13 at 13:44
  • Quote OP: "it seems finalize is clearly not meant for that". And he is right. – Marko Topolnik Aug 20 '13 at 13:45
  • I can understand that with finalize method it can't be guranteed but with phantomreference also it might not get garbage collected? – Lokesh Aug 20 '13 at 13:46
  • `PhantomReference` isn't key here: it's the fact that a specific object may linger on the heap indefinitely. In practice this occurs with objects in the tenured generation. – Marko Topolnik Aug 20 '13 at 14:06
  • @MarkoTopolnik: It will gr8 if you can give me refernce link where i can get more details on this. – Lokesh Aug 20 '13 at 14:09
  • @loki My best suggestion is to read [Effective Java, Item 7](http://www.informit.com/articles/article.aspx?p=1216151&seqNum=7), which is about finalizers, but equally applies to phantom references in the aspect of *when* the finalization is triggered, because both rely on the same mechanism for that part. – Marko Topolnik Aug 21 '13 at 09:35
1

If you want some code to be run anyway in a METHOD, just use try... finally.... The finally block is guaranteed to run. Or, in Java 7, uses the "with" block.

If you want some code to be run like the destructor of C++. I am afraid there is no such a thing in Java. The finalize method is not reliable and could not be used to handle critical missions. The way Java classes normally do is to expose a clean up method (e.g. close() of those stream classes) so that the client calls these method explicitly to do cleanup jobs.

KKKCoder
  • 903
  • 9
  • 18
  • One thing that I do see occasionally is using a `finalize` method to yell at you in your logs if the object wasn't cleaned up. It can't be depended on to actually do cleanup, but you can use it to find bugs where you didn't clean up. – Louis Wasserman Aug 20 '13 at 15:22