2017-07-19 22 views
3

我試圖模塊化我的代碼,但它涉及傳遞實現AutoCloseable的對象。讓說我有foo1和foo2的兩個公共方法:在具有相同AutoCloseable對象的多個方法中使用try-with-resources

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 
     } 
    } 
} 

我想打電話從foo1 foo2的同時,也讓其他類單獨使用foo2的。

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

這是否導致連接在調用foo2之後在foo1()中關閉?還是應該將try-with-resources放在調用方法中(比如OtherClass中的doSomething())?

+0

與值一試只是一個syntaxic糖的'嘗試.. finally'用在'finally'中調用'close'。所以是的,它會在調用'foo2'後關閉。 – litelite

+1

對不起,但foo2甚至編譯?我的IDE當然不允許我這樣做。就我在語言規範中看到的一個嘗試使用資源需要在大括號中聲明的新變量而言。 – Ordous

回答

1

是的,foo2關閉連接,所以當控制返回到foo1時它將會失效。沒有什麼不可預測的。

通過創建它們的相同代碼關閉事物是一個很好的規則。但是能夠嵌套這些東西並讓它們共享相同的連接和事務是很好的。一種解決方案是讓這些數據訪問方法中的每一個都將連接作爲參數接收,並且具有一個獲取連接並確保其關閉的外層。

你基本上試圖重新創造一點春。 Spring使您可以擁有可以使用相同連接的服務,並可以控制事務在它們之間傳播的方式和方式。這是通過使用AOP來包裝具有around建議的對象,從threadlocal數據結構獲取線程的當前連接。更容易使用彈簧(或任何容器)。

+0

你可以擴展如何在春季更好地控制它嗎?儘管這並不是我想看到Spring如何處理這個問題的原始問題的意圖。 – acvcu

2

您的foo1方法在foo2已經使用它之後關閉連接。不需要foo2關閉連接,它不應該。你讓它有一個意想不到的副作用。例如。當您在foo1內撥打conn.doSomethingElse()時,您會發現它不起作用,因爲通過撥打電話foo2關閉了連接。這違反了principle of least astonishment,因爲方法名稱沒有顯示這種副作用。

如果你叫它foo2AndCloseTheConnection那麼你明確它的作用,但我建議遵循的經驗法則創建關閉的方法應該是唯一關閉它的方法。如果你堅持這樣做,你永遠不需要看看函數內部,看看你打開的東西是否被該函數關閉。你只需要明確地關閉它。

如果你想foo2從其他方法被調用,你需要將這些方法關閉連接:

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