LoginSignup
2
3

More than 5 years have passed since last update.

try-with-resources 構文に catch(Exception e) とか catch(IOException e) は必須じゃない

Posted at

close()呼び出しを保証するtry-with-resources構文

Java6以前では以下のようにtry-finallyを使って書いていたclose()処理

Closeable r = null;
try {
  // リソースを確保
  r = getResource();
  // リソースを使用
  r.use();
} finally {
  if (r != null) r.close();
}

ですが、Java7からは以下のような書き方で大変スマートになっています。

// リソースを確保
try (Closeable r = getResource()) {
  // リソースを使用
  r.use();
}

ご存じ、try-with-resources構文です。

Closeable.close()IOExceptionを投げる

さて上記のコード片ですが、実際のプログラミングをしてみるとある重要な点が省略されていることに気付きます。そう、IOExceptionが投げ出されるのを処理していないのです。特にtry-with-resources構文を使った後者のコード、getResource()use()IOExceptionを投げないとしても全体としてはIOExceptionを投げます。なぜなら、糖衣構文で見えていないけれどもclose()呼び出しがあるから。close()IOExceptionを投げるのでそれを処理する必要があるのです。

つまり後者は実際には、

// リソースを確保
try (Closeable r = getResource()) {
  // リソースを使用
  r.use();
} catch (IOException e) {
  // 適切な処理
}

という形でなくてはいけないのです。もしくはthrows IOExceptionを付けてさらに上位へ投げるか。どちらにしろ、もともとの触れ込みから期待していたよりも若干ノイズの多いコードになります。
と、ここまではtry-with-resources構文を一度でも使ったことのある方ならすでにお気付きのことかと思います。

IOExceptionを投げないclose()を書いたっていい

さてここからが本題。
catchthrowsも使うことなく、次のような単純なコードを成立させることもできるんですよというお話。

// リソースを確保
try (MyResource r = getResource()) {
  // リソースを使用
  r.use();
}

close()が必ず成功するようなCloseable/AutoCloseableクラスというのはありえるわけです。で、そういうクラスを自作する際にCloseableを実装しつつ

public class MyResource implements Closeable {
  public void close() {
    // 必ず成功するクローズ処理
  }
}

と、throws IOExceptionなしのclose()を書くわけです。throws IOExceptionなしでもインターフェース実装は成立しています。そして、このクラスをリソースとするならば

// リソースを確保
try (MyResource r = getResource()) {
  // リソースを使用
  r.use();
}

は検査例外を吐かないものとなります。

気が付いてみれば当たり前のことなのですが、IDEを使っていると最初からthrows IOExceptionが自動的に記述されてしまうため、不要なのに付けっぱなしになり結果として不要なcatchを強要されてしまうこと、まれによくありそうなので注意喚起まで。

2
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
3