1

I have to pass a java.sql.Connection object to an anonymous inner class, which means I have to make the reference to it final. However, I am afraid of any resource leaks.

public static String foo(final Connection conn){
    ...
    @Override
    public String call() {
        ...
        return runner.query(connection, sql, scalarHandler);
    }
}

I can not understand the inner workings of the final keyword. How does it actually seal the object so it can not be changed to reference another object? Is it safe to declare a Connection object as final?

cgon
  • 1,955
  • 2
  • 23
  • 37
  • 1
    Yes, it is safe. More [here](http://stackoverflow.com/questions/4732544/why-are-only-final-variables-accessible-in-anonymous-class) – kajacx Jul 17 '14 at 22:32

3 Answers3

2

Making something final does not affect it's tendency to leak - perhaps you are confusing it with static which can (sometimes).

Declaring something final just means that once set it will not change - in fact the compiler will consider it an error if you include code that could change it.

Marking parameters and variables final so that they can be accessed from inner/anonymous classes is just a trick to get by some weird demands of anonymous classes. There is actually talk of automatically considering parameters as if they were final if they are never changed after initialization just to avoid the need to mark them so in this case.

OldCurmudgeon
  • 64,482
  • 16
  • 119
  • 213
2

How does it actually seal the object so it can not be changed to reference another object?

Careful -- final is a modifier for the reference to the object. So final "seals" the reference, not the object.

There are two ways that this "sealing" is done. One is through a compiler check of all final variables and fields. From the Java Language Specification:

It is a compile-time error if a final variable is assigned to unless it is definitely unassigned immediately prior to the assignment.

A blank final class variable must be definitely assigned by a static initializer of the class in which it is declared, or a compile-time error occurs.

A blank final instance variable must be definitely assigned at the end of every constructor of the class in which it is declared, or a compile-time error occurs.

The other way is through bytecode verification done by the JVM at class load time. The putfield and putstatic bytecode instructions throw IllegalAccessErrors if the field being operated on is final and the bytecode instruction does not occur in a particular place.

However, you have to be a bit careful here -- the final keyword only "sticks" to fields. Temporary variables and parameters lose their final-ness at compilation, so the JVM can only verify final-ness for fields if you use a non-compliant compiler or use bytecode manipulation.


Is it safe to declare a Connection object as final?

I'm not entirely sure what you mean by "safe", but if you're saying "Won't cause errors in your program", yes, for the most part (the presence of multithreading and/or compile-time constants may or may not change this answer). If you put final on a reference and your program compiles, then your program should work exactly as it has been working.

awksp
  • 11,764
  • 4
  • 37
  • 44
  • By safe I mean any unclosed connections to db? I doubt that by declaring the reference as final, it would create a new memory part apart from the original object but the copy of it (which in my case BasicDataSourceObject) Now I realize that this is not the case. Another reason to ask it here is to comfort myself since it is very important for the project that we must not leave any unclosed resource and too lazy to check the standards and think like you... – cgon Jul 17 '14 at 22:56
  • @cgon No new memory is allocated beyond the few bytes needed for a reference, because only the reference itself is copied -- not the object itself. Using `final` should not affect whether you have any open connections, because `final` only affects the reference to the object, and does not change the object itself. As for closing it, just treat the `Connection` normally. `final` shouldn't make a difference as to when you close your connection. – awksp Jul 17 '14 at 23:00
  • One day I will understand this reference thing, copying, mutations and closures. I promise myself... Thanks for your answer. have a nice one. – cgon Jul 17 '14 at 23:04
  • @cgon For references/copying, [this](https://stackoverflow.com/questions/40480/is-java-pass-by-reference-or-pass-by-value) SO question might help. Good luck with your future studies! – awksp Jul 17 '14 at 23:08
1

Is it safe? It depends on what you do with the connection after declaring it final.

I have to pass a java.sql.Connection object to an anonymous inner class

Doing this could have unforeseen consequences. If your anonymous inner class is a callback handler then it is possible that the Connection will already have been closed by the time callback is executed.

In the following example updateFooTable(...) will probably throw an exception as the Connection is likely to be closed.

public void test() {
    Connection conn = null;
    try {
        conn = DBUtils.createConnection(dataSource);
        foo(conn);
    } finally {
        DBUtils.close(conn);
    }

}

public void foo(final Connection conn) {
    MessageBox messageBox = getMessageBox("You want to update Foo?");
    messageBox.setCallBackHandler(new MessageCallback() {

        @Override
        public void yesClicked() {
                try {
                   updateFooTable(conn); //conn could be closed
                } catch (SQLException e) {
                    throw new RuntimeException(e.getMessage(), e);
                }
        }
        });
    messageBox.display();
}
Medu
  • 135
  • 2
  • 10