LoginSignup
page2
@page2

Are you sure you want to delete the question?

Leaving a resolved question undeleted may help others!

AutoCloseableインタフェースのclose()の実装について

Q&AClosed

解決したいこと

AutoCloseableインタフェースのclose()の実装についての疑問です。
以下のようなサンプルコードがあります。
AutoCloseableインタフェースを実装した自作のMyConnectionクラスでclose()の実装を行っています。
参考書などで良く見るclose()の実装です。
オーバーライドしたclose()では、特にリソースのクローズ処理を行っていません。

サンプルコード

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;

class MyConnection implements AutoCloseable{
	Connection conn =null;
	final String url="jdbc:mysql://localhost:3306/dbtest";

		public Connection getMyConnection() {
			try {
				conn=DriverManager.getConnection(url,"test","pass");
				return conn;
			}catch(SQLException e) {
				e.printStackTrace();
				return conn;
			}finally {
				System.out.println("MyConnectionのfinallyが呼ばれた");
			}
		}

		@Override
		public void close() {
			System.out.println("MyConnectionのclose()が呼ばれた");
		}
}

public class TestMain {

	public static void main(String[] args) {
		MyConnection mc = new MyConnection();
		Connection conn=mc.getMyConnection();
		try(
				mc;
				conn;
				){
			System.out.println("TestMain");
		} catch (SQLException e) {
			e.printStackTrace();
		}finally {
			try {
				if(conn.isClosed()) {System.out.println("★connは閉じられた");}
				else {System.out.println("★connは閉じられていない");}
			} catch (SQLException e) {
				e.printStackTrace();
			}
		}
	}
}

本来なら以下サンプルコードスニペットのような実装が必要と思っていました。

close()の実装に必要と思っていたコードスニペット

		@Override
		public void close() {
			System.out.println("MyConnection-close()");
			try {
				if(conn!=null) {conn.close();
				System.out.println("connは閉じられた");
				}
			}catch(SQLException e) {
				e.printStackTrace();
			}
		}

MyConnectionクラスで作成したリソースでは、close()の実装に必要と思っていたコードスニペットが実装されていないためリソースはクローズされていない。
と推測しました。
そこで、TestMainクラスのfinally句で、リソースが閉じられたか?をチェックしてみました。
結果は、以下のようにクローズされているような結果になっていました。

MyConnectionのfinallyが呼ばれた
TestMain
MyConnectionのclose()が呼ばれた
★connは閉じられた

そこで、質問なのですが、
AUtoCloseableインタフェースのclose()は実装の内容に関係なく、暗黙的にリソースがクローズされるようになっているのでしょうか?

お手数おかけいたしますが、ご教授いただければ幸いです。
何卒、宜しくお願いいたします。

0

2Answer

try(mc; conn;)

ここに conn も記述しているので、try から抜けるときに mc と conn の close がそれぞれ呼ばれているだけではないでしょうか。

0

Comments

  1. @page2

    Questioner
    @mickey_dev様
    早速にありがとうございます!
    1点伺わせていただけないでしょうか?
    >try から抜けるときに mc と conn の close がそれぞれ呼ばれている
    はい、close()が呼ばれているのですが、close()の実装は
    System.out.println();
    だけで、リソースのクローズ処理は実装されていません。
    close()の実装に「コードスニペット」のような実装は不要なのでしょうか?
  2. @page2

    Questioner
    @mickey_dev様

    こちらの表現が悪く申し訳ございません。

    AutoCloseableを実装しているBufferedReaderクラスのソースコードを見てみました。

    public void close() throws IOException {
    synchronized (lock) {
    if (in == null)
    return;
    try {
    in.close();
    } finally {
    in = null;
    cb = null;
    }
    }
    }
    と、in.close()がちゃんと実装されていました。

    ということは、AutoCloseableのclose()はリソースをクローズするような実装が必要だと思いました。
    なので、今回のサンプルコードのように、リソースをクローズしないような実装ではダメではないかと・・・。
  3. @Verclene の回答にもありますが、イメージしやすくコードを記載すると
    try() {} の動作は下記の様な感じです。(あくまでイメージです。)
    ```Java
    AutoCloseable[] closeableArray = {mc, conn}; // try(mc, conn)

    // try{} 内の処理実施後
    foreach(AutoCloseable closeable : closeableArray) {
    closeable.close(); // mc, conn のそれぞれで実施
    }

    ```
  4. @page2

    Questioner
    @mickey_dev様
    ありがとうございます。
    try-with構文のイメージありがとうございます。
    なるほどです!
    順番に処理リソースをAutoCloseable型に入れてクローズするイメージですね。
    イメージできました。本当にありがとうございました。

はい、close()が呼ばれているのですが、close()の実装は
System.out.println();
だけで、リソースのクローズ処理は実装されていません。

あなたがクローズ処理をOverrideしているのはMyConnectionのみです.
一方でソースではMyConnection.getConnection経由で取得したConnectionインスタンスをtry-with-resourcesで自分からクローズしてるよってことです.

現状のMyConnectionの実装はgetConnection()からConnectionインスタンスをユーザに提供する以上,そのConnectionインスタンスについてはユーザが責任を負うことになるので,カプセル化のメリットが少ないものになります.

Connectionをcloseする時に何かしたい程度なら,AutoClosableを実装したクラスを作るとか大がかりなことをしなくてもfinallyで十分です.

0

Comments

  1. @page2

    Questioner
    @Verclene様
    ありがとうございます!
    >Connectionインスタンスをtry-with-resourcesで自分からクローズしてる
    確かにです。言われてみるとご指摘の通りです。
    >カプセル化のメリットが少ないものになります
    なるほどです。こちらも確かにそうです。
    悶々としていた疑問が解決致しました。
    誠にありがとうございます。

Your answer might help someone💌