Using try-with-resources in multiple ways with the same AutoCloseable Object

I'm trying to modulate my code, but it involves passing in my object that implements AutoCloseable. Let's say I have two public methods foo1 and foo2:

public class MyClass {
  public void foo1() {
      // Connection implements AutoCloseable
      try (Connection conn = createConnection()) {
          foo2(conn);
          // is the connection closed or the behavior unpredictable?
          conn.doSomethingElse();
     }
  }

  public void foo2(Connection conn) {
      try (conn) {
          // do something with the Connection
      }
  }
}

      

I want to call foo2 from foo1, but also allow other classes to use foo2 separately.

public class OtherClass {
    public void doSomething() {
        MyClass myClass = new MyClass();
        myClass.foo2(createConnection());
    }
}

      

Does this cause the connection to be closed in foo1 () after calling foo2? Or should I put try-in-resources in the calling methods (like doSomething () in OtherClass)?

+3


source to share


2 answers


Your method foo1

closes the connection after foo2

using it. There is no need to foo2

close the connection, and it shouldn't. You have an unexpected side effect. For example. when you call conn.doSomethingElse()

internally foo1

, you find that it won't work because the connection was closed by the call foo2

. This is a violation of the principle of least surprise because the method name does not expose this side effect.

If you named it foo2AndCloseTheConnection

, then you will clearly state what it does, but I recommend following the rule of thumb: the method that creates the closure should be the only one to close it. If you follow this consistently, you will never have to look into a function to find out if that function is private or not. You will just close it directly.



If you want to be foo2

called from other methods, you need to close these methods:

public void doSomething() {
    MyClass myClass = new MyClass();
    try (Connection connection = createConnection()) {
        myClass.foo2(connection);
    }
}

      

+2


source


Yes, foo2 is closing the connection, so it will be invalid when control returns to foo1. Nothing unpredictable.

A good rule of thumb is to close things with the same code that creates them. But it would be nice to be able to nest these things and let them use the same connection and transaction. One solution would be for each of these data access methods to receive a connection as a parameter and have an outer layer that receives the connection and ensures that it is closed.



Basically you are trying to re-invent Spring in one go. Spring gives you the ability to have services that can use the same connection and allows you to control how transactions propagate between and between them. This is done by using AOP to wrap objects around the board, which gets the current connection for the thread from the threadlocal data structure. It is much easier to use Spring (or any other container).

+1


source







All Articles