简体   繁体   中英

Using try-with-resources in multiple methods with same AutoCloseable Object

I am trying to modularize my code but it involves passing around my object that implements AutoCloseable. Let 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 lead to the connection being closed in foo1() after the call to foo2? Or should I put the try-with-resources in the calling methods (such as the doSomething() in OtherClass)?

Your foo1 method closes the connection after foo2 has used it. There is no need for foo2 to close the connection and it shouldn't. You're making it have an unexpected side-effect. Eg when you call conn.doSomethingElse() inside foo1 , you will find it won't work because the connection has been closed by the call to foo2 . It's a violation of the principle of least astonishment because the method name does not reveal this side-effect.

If you called it foo2AndCloseTheConnection then you make clear what it does, but I recommend following the rule of thumb that the method that creates the closeable should be the only one to close it. If you follow this consistently, you'll never need to look inside a function to see whether or not something you've opened is closed by that function. You'll simply close it yourself explicitly.

If you want foo2 to be called from other methods, you need to make those methods close the connection:

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

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

It's a good rule to have things closed by the same code that creates them. But it would be good to be able to nest these things and let them share the same connection and transaction. One solution would be to have each of these data accessing methods receive the connection as a parameter and have an outer layer that gets the connection and makes sure it gets closed.

You're basically trying to reinvent Spring a bit at a time. Spring gives you the ability to have services that can use the same connection and lets you control how and whether transactions are propagated between them. This is done using AOP to wrap objects with around advice that gets the current connection for the thread from a threadlocal data structure. Much easier to use spring (or whatever container).

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM