LoginSignup
88

More than 1 year has passed since last update.

try-with-resources文の基本

Last updated at Posted at 2017-02-14

はじめに

・try-with-resources文を使う場合と使わない場合の記述例を示します。
・try-with-resources文を理解するために有効なウェブサイトへのリンクを提供します。
・try-with-resources文はJavaSE7以降で使用可能です。
・try-with-resources文が利用できるクラスは、AutoCloseableインタフェースおよびそのサブインタフェースであるCloseableインタフェースの実装クラスに限られます。

try-with-resources文の記述例

try-with-resources文を使わない場合

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;

public class TryWithResources {
    public static void main(String[] args) {

        String inFilePath = "D:\\A.txt";
        String outFilePath = "D:\\C.txt";

        FileInputStream in = null;
        FileOutputStream out = null;

        try {
            in = new FileInputStream(inFilePath);
            out = new FileOutputStream(outFilePath);
            int c;

            // データをコピーする
            while ((c = in.read()) != -1) {
                out.write(c);
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (in != null) {
                try {
                    in.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (out != null) {
                try {
                    out.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

ポイント
1.finally句がなくてもコンパイルエラーにはならないので、リソース開放漏れの危険性がある。
2.try句とfinally句の両方で同じリソースを指し示すことが必要なので、変数はtry-catch-finallyの外側で宣言する。
3.finally句のcloseメソッド呼出でIOExceptionの可能性があるため、try-catchのネストが必要。

try-with-resources文を使う場合

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;

public class TryWithResources {
    public static void main(String[] args) {

        String inFilePath = "D:\\A.txt";
        String outFilePath = "D:\\C.txt";

        try (FileInputStream in = new FileInputStream(inFilePath);
                FileOutputStream out = new FileOutputStream(outFilePath)) {
            int c;

            // データをコピーする
            while ((c = in.read()) != -1) {
                out.write(c);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

ポイント
1.基本的にリソースは自動開放。1

2.変数のスコープはtry句に限られる。
3.close時の例外は基本的には考慮不要。

参考サイト

Oracle Java SE Documentation try-with-resources文
TASK NOTES 【Java】try-with-resources構文について
try-catch-finally、try-with-resources、そして発生した例外たち

ちなみに

FileInputStreamなどのクラスはfinalizeメソッドの中でcloseを呼出しているため、リソース開放漏れのバグには気づきにくい(起こりにくい)のです。ただし、開放をGCに任せるのは非効率だしお作法としてよろしくないので、try-with-resourcesを利用しましょう。

FileInputStream.java
package java.io;

import java.nio.channels.FileChannel;
import sun.nio.ch.FileChannelImpl;


public
class FileInputStream extends InputStream
{

===========================省略===========================

    /**
     * Closes this file input stream and releases any system resources
     * associated with the stream.
     *
     * <p> If this stream has an associated channel then the channel is closed
     * as well.
     *
     * @exception  IOException  if an I/O error occurs.
     *
     * @revised 1.4
     * @spec JSR-51
     */
    public void close() throws IOException {
        synchronized (closeLock) {
            if (closed) {
                return;
            }
            closed = true;
        }
        if (channel != null) {
           channel.close();
        }

        fd.closeAll(new Closeable() {
            public void close() throws IOException {
               close0();
           }
        });
    }

===========================省略===========================

    /**
     * Ensures that the <code>close</code> method of this file input stream is
     * called when there are no more references to it.
     *
     * @exception  IOException  if an I/O error occurs.
     * @see        java.io.FileInputStream#close()
     */
    protected void finalize() throws IOException {
        if ((fd != null) &&  (fd != FileDescriptor.in)) {
            /* if fd is shared, the references in FileDescriptor
             * will ensure that finalizer is only called when
             * safe to do so. All references using the fd have
             * become unreachable. We can call close()
             */
            close();
        }
    }
}
  1. try-with-resourcesでリソース解放されないパターン

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
88