【弊社新人に向けて】開いたら必ず閉じよう

# 何が言いたいの？
**開いたら必ず閉じよう**ということです。
ファイルが開きっぱなしになっていると、場合によってはファイルの読み書きが行えなくなります。
それでは困りますね。

# 例えば？
`FileReader`クラスや`FileWriter`クラスを用いて、テキストファイルを読み書きする場合などです。
昔は`BufferdReader`クラスなんかを使っていましたが、今どきは`Scanner`クラスなるものが使われているようですね。

実際にテキストファイルの内容を読み込み、内容をコンソールに出力するプログラムを以下に示します。

```java:サンプルプログラム
import java.io.File;
import java.util.Scanner;

public class FileOpenTest {
	public static void main(String[] args) {
		try {
			// テキストファイルを開く
			Scanner scanner = new Scanner(new File("F1歴代チャンピオン一覧.csv"));

			// 1行ずつ読み込み、コンソールに出力
			while (scanner.hasNextLine()) {
				System.out.println(scanner.nextLine());
			}

			// テキストファイルを閉じる
			scanner.close();

		} catch (Exception e) {
			e.printStackTrace();
		}
	}
}
```
```bash:出力内容
1950年,ジュゼッペ・ファリーナ,アルファロメオ,－
1951年,ファン・マヌエル・ファンジオ,アルファロメオ,－
1952年,アルベルト・アスカリ,フェラーリ,－
1953年,アルベルト・アスカリ,フェラーリ,－
1954年,ファン・マヌエル・ファンジオ,マセラティ/メルセデス,－
1955年,ファン・マヌエル・ファンジオ,メルセデス,－
1956年,ファン・マヌエル・ファンジオ,フェラーリ,－
1957年,ファン・マヌエル・ファンジオ,マセラティ,－
1958年,マイク・ホーソーン,フェラーリ,ヴァンウォール
1959年,ジャック・ブラバム,クーパー・クライマックス,クーパー
（内容はwikipediaより借用）
```

無事、テキストファイルの読み込みに成功しました🎉:clap:

# では終わりません
ほとんどの場合、読み込んだ行に対して何らかの加工を行います。

```java:何らかの処理
			// 1行ずつ読み込み、何らかの処理を行う
			while (scanner.hasNextLine()) {
				anyProcess(scanner.nextLine());
			}
```

もし、この処理内で例外が発生したらどうなるでしょう。
今回の場合`try`文で処理全体を囲っているので、`catch`ブロックへ処理が移ります。

```java:例外を補足
		} catch (Exception e) {
			e.printStackTrace();
		}
```

これで無事に例外を補足し、エラーログを出力することができました🎉:clap:

# ではありません
一つ忘れていることがあります。
例外が発生したら`catch`ブロックへ処理が移る...

そうです。
**ファイルが閉じられていません**😲

```java
		try {
			// テキストファイルを開く
			Scanner scanner = new Scanner(new File("歴代チャンピオン一覧.csv"));

			// 1行ずつ読み込み、何らかの処理を行う
			while (scanner.hasNextLine()) {
				anyProcess(scanner.nextLine());  // エラーが発生
			}

			// テキストファイルを閉じる
			scanner.close();                     // 実行されない!!

		} catch (Exception e) {
			e.printStackTrace();                 // ここまで処理が飛んでしまう
		}
```

# どうすればいいの

何がなんでもファイルを閉じたい...
そこで`finally`ブロックの登場です。

`finally`ブロックは、処理に**エラーがあったか無かったかに関わらず必ず実行**されます。
`finally`ブロックを追加したコードを以下に示します。

```java:finally&nbsp;ブロックを追加
import java.io.File;
import java.util.Scanner;

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

		// try文のブロックの外に変数を宣言する
		Scanner scanner = null;

		try {
			// テキストファイルを開く
			scanner = new Scanner(new File("歴代チャンピオン一覧.csv"));

			// 1行ずつ読み込み、何らかの処理を行う
			while (scanner.hasNextLine()) {
				anyProcess(scanner.nextLine());
			}

			// テキストファイルを閉じる
			scanner.close();

		} catch (Exception e) {
			e.printStackTrace();

		} finally {
			// テキストファイルを閉じる
			if (scanner != null) {
				scanner.close();
			}
		}
	}
}
```

まず、`try`文のブロックの外側に`Scanner`クラスの変数を宣言します。
`try` `catch` `finally`は、それぞれ異なるスコープと見なされるためです。
`try`ブロックの中で宣言された変数は、`finally`ブロックから**参照することができない**のです。

その後、実際にファイルを閉じていきます。
この時、**`scannar`変数が`null`かどうか**の判定を忘れてはいけません。
`scannar`変数は宣言時に`null`を格納しています。

```java:初期値には&nbsp;null&nbsp;を設定
		// try文のブロックの外に変数を宣言する
		Scanner scanner = null;
```

`null`に対してメソッドの呼び出しを実行すると、これまた別の例外が発生してしまいます。

# 書いてる途中で知ってしまった
`try-with-resources`文なるものがあるようです
どう考えてもこっちの方が便利ですよね。`C#`の`Using`みたい。
参考：[Oracleのサイト](https://docs.oracle.com/javase/jp/7/technotes/guides/language/try-with-resources.html)

# まとめ
少々ばかり内容が古臭い気がしますが...まあ良いでしょう。
開いたら閉じる。便器のフタと同じです。