クリリンでもわかるJava入門（後編）

[前回のドラゴンボール](https://qiita.com/oh_yeah_sayryo/private/ef40e41e973eedff523e)(前編)

オブジェクト指向の魅力的な機能から始めていく

# カプセル化（オブジェクト指向3大機能その①）
オブジェクト指向の3大機能（カプセル化・継承・多様性）の1つ。
**アクセス制御を行うことでミスを防ぐ**。
##### 4種のアクセス修飾子

| 制限度 | 名前 | コードで指定方法 | 許可範囲 |
|:-:|:-:|:-:|:-:|
| 厳しい  | private  | private    | 自分自身のクラスのみ  |
| ↑  | public private    | 何も書かない  | 自分と同じパッケージのクラスのみ  |
| ↓  | protected  | protected    | 自分と同じパッケージor自分を継承したクラス  |
| 緩い  | public  | public  | 全てのクラス  |
一般的にフィールドは private、メソッドは publicにする。
※クラスはpublic か public privateしか使えない。

フィールドがprivateだと他クラスから変更ができない。変更するときは getterメソッドと setterメソッドというものを用意する。
getterで取得、setterで上書き。
基本的なメソッドの命名は
「get/set + フィールドの一文字目を大文字()」となる。
getter()のみを使えばRead only（読み込みのみ、上書き不可）のフィールドを実現できたりメリットがある。

```sample.java
public class Hello{
    private String name;

    public String getName(){
        return this.name;
    }

    public void setName(String name){
        this.name = name;
    }
}
```
↓setterでフィールドへの上書き検査もできる。

```sample.java
private String name;

public void setName(String name){
    //名前がnullなら中断
    if(name == null){
        throw new IllegalArgumentException("名前がnullの為、処理中断")
        this.name = name;
    }
```
# 継承（オブジェクト指向3大機能その②）
**extends で他クラスを継承し、内容を継ぐ**ことができる。

```.java
public class Angel extends Human {
}
```
つまり、Angelクラスをインスタンス化したとき Humanクラスのメソッド（＆フィールド）が使える。

```.java
Angel Ag = new Angel();
Ag.run(); //Humanクラスで宣言したrunメソッド
```
このクラスの継承関係では元となった親クラスHumanを**スーパークラス**という。
継承済みAngelを他クラスに継承させることもできる。
※ただし、１クラスで**複数同時**継承はできない（1回1個まで）。
# オーバーライド
↑に記述したAngelクラスで継承したHumanクラスの一部を変更したいときは、
再定義することで上書きできる。
※Humanクラスに影響はない。
※親がrun(String s)メソッドで子がrun(String s,int a)メソッドならこれはオーバーライドではなくオーバーロードなので別メソッドでありメソッドの上書きにはならない。

```Angel.java
public void run(){
    System.out.println("runメソッドの内容が上書きされた")
}
```
子クラスでオーバーライド（上書き）されたくないときは
「public **final** class」のように**final**を付ける。

上書き前のrunメソッドも使いたいという場合は、
**super**を利用しスーパークラス（親）を呼び出せる。

```.java
super.run(); //メソッド
super.name; //フィールド
```
※「親-子-孫」 の継承関係の場合、孫から子へはsuperで呼べるが、孫から親へはsuperでは呼べない。親をsuperで呼びたいなら、子にオーバーライドさせず、superで子を呼べば結果親の処理を呼ぶことになる。
# 継承とコンストラクタ
インスタンス化（new）すればコンストラクタが自動で呼ばれるが、
継承しているとスーパークラスのコンストラクタから処理される。
例えば、Humanクラスを継承したAngelクラスをインスタンス化したとき、
Angelのコンストラクタ等の処理の前に、Humanにコンストラクタがあればそちらが優先処理される。

実はAngelクラスでHumanクラスのコンストラクタを「**super()**」で呼んでいる。
書かなくても自動で暗黙のsuper()が呼ばれる。

```Angel.java
public class Angel extends Human {
    //省略できるが暗黙的に呼ばれる
    public Angel(){ //Angelのコンストラクタ
        super(); //Humanのコンストラクタを呼ぶ
    }
}
```
※super()はthis()同様、コンストラクタの先頭行にしか記述できない。
# 正しい継承
正しく継承をするには「is-a」(子は親の一種である)を守る。

例：3つ

- スーパークラス：Human（人型）　サブクラス：Angel

　〇 Angelは人型の一種である。

- スーパークラス：Food　サブクラス：Sushi

　〇 SushiはFoodの一種である。

- スーパークラス：Car　サブクラス：Engine

　× EngineはCarの一種である。
　　より具体的な車（スーパーカー、ベンツ等）なら〇

親から子へは**具体的に特化**していき、
子から親へは**抽象的に汎化**していく。

間違った継承をするとクラスに矛盾が生じたり、オブジェクト指向の1つ「多様性」を利用できなくなる。
# 高度な継承
他の開発者向けにスーパークラスを作るとなれば、様々な不都合が出てくる。
3つの不都合に対する解決法を挙げていく。

#### ①詳細未定（抽象）メソッドの宣言
他に開発者2人が 悟空クラスと ベジータクラスを作ろうとしている。
気の色や髪色、似たフィールドがある為、継承用にスーパーサイヤ人クラスを作ってあげる。
かめはめ波メソッドを作ろうとしたが、それぞれで威力が違う為定義できない。

```SuperSaiyajin.java
public class SuperSaiyajin {
    public void kamehameha (Saibaiman s){
        s.hp -= ??;
    System.out.println("サイバイマンのHPが？？減った！")
    }
}
```
とりあえず、オーバーライドして上書きしてもらう事にして、
かめはめ波メソッドの処理を削除すれば良いと考えるが、
**何も行わないメソッドだと思われてしまうのを避ける為**に「abstract(アブストラクト)」を使う。
日本語で「抽象的・あいまい」という意味。
「{}」を付けずに「；」を付ける。
abstractの付いたメソッドを抽象メソッドという。

```.java
public abstract void kamehameha (Saibaiman s);
```
#### ②抽象メソッドを含むクラスの宣言
1つでも abstract を含むメソッドがるときクラスにも abstract を付ける必要がある。（無いとエラー）

```SuperSaiyajin.java
public abstract class SuperSaiyajin {
    public abstract void kamehameha (Saibaiman s);
}
```
abstract の付いたクラスは抽象クラスと呼ばれ、new（インスタンス化）できない。（するとエラー）
**継承（extends）用に作成したスーパーサイヤ人クラスが間違ってインスタンス化されない**ようになる。
#### ③オーバーライドの強制
悟空クラスでかめはめ波メソッドの**オーバーライド（上書き）を忘れる可能性**がある。
しかし、上の①②を実践していればエラーが起こるので忘れることがなくなる。
なぜなら、スーパーサイヤ人を継承しているということは「抽象メソッドのかめはめ波メソッド」を含む。
抽象メソッドを含むクラスは abstract が必要。
オーバーライドに気づき、かめはめ波メソッドを抽象化せずオーバーライドすればエラーは消える。

##### アクセス修飾子 protected について
protected の許可範囲は自分と同パッケージか、自分を継承したクラス。
自分のパッケージだけなら public で良いわけで、違うパッケージかつ継承クラスに protected を
使うことになるので利用局面は少ないといえる。

##### [高度な継承](#高度な継承)をまとめると、
各自で絶対にオーバーライドして欲しいメソッドは抽象メソッド（abstract）にすると良いということ。
オーバーライドしなかったときのエラー文
```Goku is not abstract and does not override abstract method kamehameha() in SuperSaiyajin```

# インタフェース
特に抽象度が高いクラスをインタフェースという。
インタフェースにできる２条件
①すべて抽象メソッドである。
②基本的にフィールドを持たない。
↑のSuperSaiyajin.javaはインタフェースにできる。
インタフェースのメソッドは自動で「public abstract」になる為、省略可能。

```SuperSaiyajin.java
public interface class SuperSaiyajin {
    //public abstract は省略可能
    void kamehameha (Saibaiman s);
}
```
基本的にフィールドを持たないと書いたが、「public static final（定数）」だけ宣言が許可されている。
これもメソッド同様、自動で保管（public static final（定数）扱い）されるので省略可能。
例：`int power = 1000000;`

※もちろんインタフェースも抽象的に変わりない為インスタンス化不可。

# インタフェースの実装
インタフェースの継承は extends ではなく、**implements** を使う。
implementsは日本語で「実装する」という意味。
インタフェース（抽象的で未確定）をオーバーライドで実装確定するイメージ。

```Gokuu.java
public class Gokuu implements SuperSaiyajin {
}
```

# インタフェースの必要性
継承は複数クラス同時にできないと言いました。
理由は例えば、
かめはめ波メソッドを持つ悟空クラスと、チチクラスを
継承時点で悟飯クラスは威力が違うどっちのかめはめ波メソッドを使えばいいのか衝突し問題になる。

そこで両親がインタフェース（＝抽象メソッドしか存在しない）なら衝突せず、悟飯自身でオーバーライドしてかめはめ波の威力を決定できる。
よってインタフェースは多重継承が可能。

```Gohan.java
public class Gohan implements Gokuu, Chichi{
}
```

# インタフェースとextendsの使い分け
悟空クラスをインタフェースとして次を見てください。

```Gohan.java
public interface class Gohan extends Gokuu {
}
```
悟空はインタフェースだから implements で継承じゃないの？となる。
実は implements を使うのはインタフェースを継承したクラスでオーバーライド（実装）するときだけ。
この悟飯クラスはよく見たらインタフェースだ。
悟空インタフェース（未確定）⇒悟飯インタフェース（未確定）なので確定（実装）にはなっていない。
よってただの継承（extends）である。

implements を使うのは未確定から確定になるときのみ。
言い換えると、クラスがインタフェースを継承するときのみ。
**インタフェース⇒クラス　はimplements**。

#### extendsとimplementsは同時に使える
例：`public class Gohan extends SuperSaiyajin implements Gokuu, Chichi{`

# 多様性（オブジェクト指向3大機能③）
多様性（polymorphism）はポリフォーフィズムとも呼ばれる。
カプセル化は private、継承は extends と、文法があるが多様性にはない。
ここでの**多様性とは曖昧に捉えることでメリットを得られる方法**のこと。

スーパーサイヤ人クラスを親とする子クラス「悟空クラス」をインスタンス化すると（継承関係）

```.java
Gokuu g = new Gokuu();
```
↑のようになるが、スーパーサイヤ人型にもできる。

```.java
SuperSaiyajin g = new Gokuu();
```
悟空はスーパーサイヤ人クラスを継承している為、これが可能になる。
つまり、親の型でインスタンス化ができる。
インタフェースのような抽象クラスはインスタンス化できないと言ったが、
ここでは型として利用しているだけで問題はない。

悟空はスーパーサイヤ人の一種である。
これが逆だと矛盾が生じる為、正しく継承する必要があった。（項目：正しい継承）

# 型を曖昧にしたときの変化
悟空クラスを親クラス（スーパーサイヤ人）にしたときどう変化するのか。

```.java
//1
public abstract class SuperSaiyajin {
    public abstract void kamehameha(); //スーパーサイヤ人はかめはめ波を使える。
}
//2
public class Gokuu extends SuperSaiyajin {
    public void kamehameha(){ //かめはめ波のオーバーライド
        System.out.println("100ダメージ");
    }

    public void kaiouken(){  //悟空は界王拳を使える。
    }
}
//3
public class Main{
    public static void main (String[] args){
        Gokuu g = new Gokuu();
        SuperSaiyajin s = g; //悟空インスタンスをスーパーサイヤ人型へ代入

        s.kamehameha();
        s.kaiouken();
    }
}
```
↑の`s.kamehameha()`は成功するが、`s.kaiouken()`はエラーになる。
スーパーサイヤ人クラスにかめはめ波はあるが、界王拳はない為使えない。
実は以下のようなルールがある。

**型とインスタンス**

- **使えるメソッドは型で決まる。**

- **メソッドの処理は中身（インスタンス）で決まる。**

つまり、スーパーサイヤ人クラスで適当に界王拳メソッドを作れば、
呼び出すことが可能になり、処理は悟空クラスでオーバーライドした内容で動作しエラーは起こらない。

# 型を途中で変える
↑のソースで、スーパーサイヤ人は誰でも界王拳が使えるわけじゃないし
やっぱり悟空クラスにだけ界王拳を使えるようにしたい！となる場合がある。
そんなときは**キャスト**を使う。

```.java
SuperSaiyajin s = new Gokuu();
Gokuu g = (Gokuu) s; //スーパーサイヤ人型を悟空型へ変換し代入
```
今回のような「曖昧な型を厳密な型に代入」することを**ダウンキャスト**とって失敗が危惧される。
例えば、悟空インスタンスのスーパーサイヤ人型をチチ型へ変換し代入したときもコンパイル時にエラーが出ない。
しかし、動作させた瞬間に**ClassCastException**というエラーが発生する。
キャストによる強制代入の内容が間違っているという意味のエラー。

このエラーを確実に回避するには、ある演算子を使用する。

**instanceof演算子**
`変数 instanceof 型名`　（変数を型名に代入可能ならばtrue）

```.java
SuperSaiyajin s = new Gokuu();
if (s instanceof Gokuu){
    Gokuu g = (Gokuu) s;
}
```

より詳細な説明は以下参照。

https://qiita.com/tukine_T/items/4461cb75adc36fa4c0b6

# 多様性のメリット
多様性を用いてインスタンスを曖昧に捉えることで
呼び出せるメソッドが減ったりとメリットがないようだが、
具体的なコードで説明していく。
スーパーサイヤ人1名、ナメック星人2名のPT（パーティー）が仙豆で100HP回復するプログラム。

```.java
public class Main {
    public static void main (String[] args){
        SuperSaiyajin s1 = new SuperSaiyajin();
        Namekkuseijin n1 = new Namekkuseijin();
        Namekkuseijin n2 = new Namekkuseijin();

        //仙豆で回復
        s1.setHp( s1.getHp() + 100);
        n1.setHp( n1.getHp() + 100);
        n2.setHp( n2.getHp() + 100);
    }
}
//前提：スーパーサイヤ人もナメック星人も抽象クラス「Character」を継承している。
//Characterクラスはhpフィールドとそのgetter,setterを持つとする。
```
このプログラムの回復処理は2つの問題がある。

- コードに重複が多い　⇒　記述が面倒。変数名を間違えそう。

- 将来的に多くの修正が必要　⇒　PT人数の増加による行追加。インスタンス名が変更による変数名修正。

これは多様性と配列の組み合わせで解決可能。

```.java
public class Main {
    public static void main (String[] args){
        Character[] c = new Character[3]; 
        c s1 = new SuperSaiyajin();
        c n1 = new Namekkuseijin();
        c n2 = new Namekkuseijin();

        //仙豆で回復
        for (Character ch : c){ //拡張for文
            ch.setHp( ch.getHp() + 100);
        }
    }
}
```
次は、引数を曖昧にした活用例を紹介
悟空がサイバイマンと魔人ブウに攻撃するプログラム。
以下のように処理を分けて書くはず。

```Gokuu.java
public clss Gokuu extends SuperSaiyajin {
    public void kamehameha (Saibanman s){}; //サイバイマンにかめはめ波を撃つ処理

    public void kamehameha (Majinbuu m){}; //魔人ブウにかめはめ波を撃つ処理
}
```
しかし、敵が増えるごとにコードの追加が必要になる。
これも多様性で敵（Enemy）を曖昧にすれば、以下で済む。

```Gokuu.java
public clss Gokuu extends SuperSaiyajin {
    public void kamehameha (Enemy e){}; //敵にかめはめ波を撃つ処理
}
```
これで**Enemyクラスを継承している敵**なら誰にでもかめはめ波を撃てる。
引数の渡し方は↓のような感じで良い。

```.java
Gokuu g = Gokuu();
Saibaiman s = Saibaiman();
Majinbuu m = Majinbuu();

g.kamehameha(s); //サイバイマンにかめはめ波
g.kamehameha(m); //魔人ブウにかめはめ波
```

#### 多様性の最大のメリット
多様性の真価は、
**異なるインスタンスを曖昧に捉えることでまとめて使える**ことと
**動作は型でなくインスタンスのメソッドで決まる**ことを組み合わせたときに発揮される。

```例.java
public class Main {
    public static void main(String[] args){
        SuperSaiyajin [] superSaiyajin  = new SuperSaiyajin[3];
        superSaiyajin  [0] = new Gokuu(); //悟空は奥義メソッドは身勝手の極意
        superSaiyajin  [1] = new Beji-ta(); //ベジータの奥義メソッドはファイナルフラッシュ
        superSaiyajin  [2] = new Bejitto(); //ベジットの奥義メソッドはベジットソード

        for (SuperSaiyajin su : superSaiyajin ){
            su.ougi(); //それぞれ所有する奥義を使う。
        }
    }
}
```
```実行結果.
悟空は奥義：身勝手の極意を使用した。
ベジータは奥義：ファイナルフラッシュを使用した。
ベジットは奥義：ベジットソードを使用した。
```
全体から多様性の構図と本質を見る。
指示側は「サイヤ人達、とりま奥義使え」といい加減なのに対し、
一方、キャラクター（サイヤ人）側は「奥義使え」と言われただけで独自の奥義を使えている。
このように、**呼び出し側は相手を同一視し、同じように呼ぶ**のに、
**呼び出される側は、決められた動きをする**という特性から「多様性」と名付けられた。

# Javaの標準クラス
日時を扱う基本形式2つ

- 形式1：long型の数値

　　基準日時である1970年1月1日0時0分0秒（エポックと呼ばれる）から経過したミリ秒数で表現する方法。
　　long値：1316622225935　は2011年9月22日・・・を意味する。
　　しかし、人間では日付が読めないことや、longは単に数字の格納にも使われ中身が日時情報と判断がつかない。
　　System.currentTimeMiilis()で現在時刻取得。

- 形式2：Date型のインスタンス

　　long型の課題克服で広く用いられているのが java.util.Dateクラス。
　　内部でlong値を保持しているだけだが、**Date型の変数は日時情報であると判断がつく為、Javaで最も利用される**。

```Date例.java
import java.util.Date;
public class Main {
    public static void main(String[] args){
        Date now = new Date(); //現在時刻取得
        System.out.println(now);
        System.out.println(now.getTime());
        Date p = new Date(1316622225935L); //long型なので「L」が必要
        System.out.println(p);
    }
}
```
```実行結果.
Thu Jan 14 07:25:22 JST 2021　👈この行はリアルタイム次第
1610576722675
Thu Sep 22 01:23:45 JST 2011
```
人間が扱いやすい2つの形式

- 形式3：String型のインスタンス

　　SimpleDateFormatクラスで書式の指定ができる。(例：yyyy年MM月dd日も可能)

```SimpleDateFormat例.java
import java.text.SimpleDateFormat;
import java.util.Date;
public class Main {
    public static void main(String[] args){
        Date now = new Date(); //現在時刻取得
        SimpleDateFormat f = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss"); //書式指定
        String s = f.format(now); //フォーマットをあてる
        System.out.println(s);
        //逆に指定日時（String型）からDate型にもできる。
        Date d = f.parse("2020/01/14 01:01:01");
    }
}
```
- 形式4：6つのint形式

　　月や秒、それぞれを指定できる。
　　`変数.set(年,月,日,時,分,秒)`or`変数.set(Calendar.〇〇, 値)`で指定。
　　※Calendarで月の指定には注意。0始まりなので1月なら`set(Calendar.MONTH, 2)`となる。

```Calendar例.java
import java.util.Calendar;
import java.util.Date;
//public ～割愛
Date now = new Date(); //現在時刻取得
Calendar c = Calendar.getInstance();
c.setTime(now); //setTime()でDate型をリアルタイムセット
c.set(2030,8); //set()で年・月を上書き
c.set(Calendar.YEAR, 2020) //set()で年を上書き
int s = c.get(Calendar.SECOND) //get()で秒を取得
``` 

# 暗黙の継承
メソッドもフィールドも一切定義していないクラスでtoString()を呼び出せるのは、
全てのクラスはjava.lang.Objectを継承しているからだ。
実質：`public class 〇〇 extends Object`

Objectクラスの存在価値は
最低限必要なメソッド（toString()、.equals()）が使える他に、
多様性が利用できる利点がある。

```.java
public class Main {
    public static void main(String[] args){
        Object o1 = new Gokuu(); //全インスタンスはオブジェクトの一種であると言える。
    }
}
```

# ラッパークラス
Javaの型には基本型と参照型がある。基本型（String以外）では数値や文字の格納、値を使った演算処理が行える。
しかし、値に対する操作を行う手段（メソッド）は用意されていない。また、複雑な処理をより簡易に行えるAPIなどを利用しようとした場合、基本型は引数の対象外となるため使用できない。

そこで基本データ型の値をラップ（＝包み込む）してオブジェクトとして利用できるようにするクラスが用意されている。
それらを**ラッパークラス**と呼ぶ。

例えば「数値を文字列に変換したい」といった場合、ラッパークラスを利用して変換、といったことも行える。

基本データ型：int　の　ラッパークラス：java.lang.Integer

```.java
//ラッパークラスを利用するパターン
int i = 84;
Integer o = new Integer(i);
String str = o.toString(); //toStringはint（基本型）には使用できないが変数oはオブジェクトだ
//利用しないパターン
int i = 84;
String str = String.valueOf(i);
```
2つの違いは、valueOfは値がnullならnullを返すが、toStringはエラーが起こる為注意！
（※ラッパークラスはByte,Shot,Integer,long,Float,Double,Boolean等がある。）

# エラーの種類と対応策
とりあえず動作するプログラムを作るのは簡単だが、エラーを起こさないプログラムを作るのは難しい。
いかなる場合も不具合のないプログラムを目指す必要がある。
#### Javaでの不具合は主に3種

- ①文法エラー（syntax error）

　　文字・文法間違え、セミコロン抜け等。
　　⇒エラー文の箇所を修正。

- ②実行時エラー（runtime error）

　　文法に問題がない為、コンパイル時は成功するが、実行中にエラーが出る。
　　⇒対策処理を記述しておく。

- ③論理エラー（logic error）

　　文法に問題がなく、強制終了することもないが内容がおかしい。（例：電卓ソフトの計算結果がおかしい）
　　⇒自力で探しコードを修正。

#### 例外的状況
①と③はテスト時のコード修正で予防できるが、②実行時エラーはそうはいかない。
そもそも実行時エラーは想定外の事態の発生で起こる。
この「想定外の事態」を**例外的状況（exceptional situation）**又は**例外（exception）**という。

**例外パターン例**
・パソコンのメモリ不足
　　開発環境では問題なく、本番環境の動作中にメモリ不足。
・存在すべきファイルがない
　　誤って消されていた。
・nullが入っている変数のメソッドを呼び出した。
　　ユーザーの想定外の操作により、本来入る予定のないnullが変数に入り、その変数を使用するメソッドを呼び出した。
　　（if文でnullチェックはできるが、全ての処理に対しチェックするのは現実的ではない。）

**これら全て開発時では例外的状況の発生を予防できない。**
しかし、例外的状況発生後の対策は可能。

# 例外処理
例外的状況に陥ったときに備えた対策を**例外処理**という。

従来型の例外処理
処理①に対してif文でチェック
処理②に対してif文でチェック
と、1つの処理毎にチェックが必要で面倒。本来の処理の行もわかりづらい。

#### try-catch文
try-catch文でまとめてチェックできる。
tryは通常通り流れ、例外が発生したところでcatchブロックに移る。

```.java
try{
    //処理①
    //処理②
}catch(・・・　変数){
    //・・・という例外処理が発生すれば動作する。
}
```
↑のコード「・・・」には例外的状況を表すクラス「**例外クラス**」が入る。

#### 例外の種類
- ①Error 系例外

　　catchする必要なし。
　　**回復の見込みがない致命的な状況。**
　　例：OutOfMemoryError(メモリ不足)、ClassFormatError(クラスファイル破損)

- ②Exception 系例外

　　catchすべき。
　　java.lang.Excepton(RunTimeException以外)を親に持つ。
　　**想定し対処を考える必要がある例外的状況。**
　　例：IOException(ファイル等が読み書き不可)、ConnectException(ネットに接続できない)

- ③RunTimeException 系例外

　　catchしなくてもよい。
　　java.lang.RunTimeExceptionを親に持つ。
　　**必須とは言えない例外的状況。**
　　例：NullPointerException(変数等がNull)、ArrayIndexOutBoundsException(配列の添え字不正)

②のException 系例外の発生可能性がある箇所はtry-catch文で囲んでいないと、
コンパイル時に「例外 java.io.IOException は報告されません。～」と怒られる。
これを**チェック例外**という

#### 発生する例外の調べ方
APIに含まれるクラスは例外が発生する可能性があるメソッドが多くある。
発生する例外はAPIリファレンスに掲載されている。
例：
APIが FileWriter なら「throws IOException」と書かれている為、
try-catch文で`catch(IOException e)`としてやる。

↑１行上の「変数e」にはエラー情報が詰まっている（文字はeである必要はない）。
例外インスタンスと呼ばれ、`e.getMessage()`のようにも使える。

**例外インスタンスが必ず備えているメソッド**

| メソッド | 意味 |
|:-:|:-:|
| getMessage()  | エラーメッセージの取得  |
| printStackTrace()  | スタックトレースを画面に出力  |
※スタックトレース：プログラムの起動内容や例外内容等が記録された情報

# 様々なcatch構文
try-catch-catchのように複数の例外をキャッチすることも可能。
また、抽象的な例外クラスを指定することもできる。
Exception 系例外なら親に java.lang.Exceptonを持つので
`catch(Exception e)`でException 系例外全てをキャッチできる。

#### 後付け処理の対応
次に、ファイルを開いて⇒文字を書いて⇒ファイルを閉じるプログラムがある。

```.java
try {
    FileWriter fw = new FileWriter("data.txt");
    fw.write("hello!");
    fw.close();
} catch (Exception e) {
    System.out.println("エラー発生");
}
```
これには問題点がある。
ファイルは開いたら閉じるのが決まり。
write()で上書きした後に、もしディスク容量が不足した場合に例外が発生し
catchへ移動するのでclose()が飛ばされる。

その対策でclose()をtry-catch構文の外へ移動し、
try-catch後に閉じれば問題ないかと思うが、NullPointerException等のcatchしていない例外が発生すれば
その時点で処理が止まり、close()が流れない。

必ず最後に実行しなければならない処理には
**try-catch-finally**を使う。

```.java
} finally {
    fw.close(); //例外が起こっても行う処理
}
```
finallyが必須の状況は、今回のようなファイルやデータベース接続、ネットワーク接続等

※java8からはfinallyを使う場合、
try-finallyよりもtry-with-resourcesを使うと良い。[try-finallyよりもtry-with-resourcesを使おう](https://qiita.com/NagaokaKenichi/items/124f0e14ce5dfcbd0b6b)

# 例外の伝搬
例外はcatchしないと強制終了することがわかる。
では、mianメソッドでaメソッドを呼び出し、aメソッドはbメソッドを呼び出したが
bメソッドで例外が発生した場合どういう流れで処理されるか。

main() ⇒ a() ⇒ b() ✖例外発生

b()でcatchできなければa()へ、a()でも無理ならmain()へ、それでも無理なら強制終了となる。
この現象を**例外の伝播**と呼ぶ。
（例えば、a()でb()を呼び出すとき例外が発生する想定をしcatch構文を記述していれば防げた。）

Exception 系例外はキャッチが必須の為、例外の伝播は基本発生しない。
しかし、**スロー宣言**を行えば呼び出し元へ例外を伝播できる。
`throws 例外クラス1, 例外クラス2...`（throw：意味　投げる）

```.java
public static void b() throws IOException{
    //本当はtry-catch構文でIOExceptionを拾う必要があるが
    //例外発生した場合は、俺を呼び出したやつに投げるぜ！（責任丸投げ）
    FileWriter fw = new FileWriter("data.txt");
}
```
これで、コンパイル時にtry-catchがないと怒られることはないが、
呼び出し側が（try-catchする）責任を取るので注意が必要。

# 例外を発生させる
**例外を投げる**とも言う。
`throw new 例外クラス名（"エラーメッセージ"）;`
※スロー宣言は throw **s** で「s」があるから間違わないように。

```.java
if ( name == null) {
    throw new NullPointerException("null発生！");
}
```

#### オリジナル例外クラスの定義
チェック例外（Exception 系例外）を継承すればオリジナルエラーメッセージの例外を作れる。
（非チェック例外で作成する状況はほとんどない。）

```OrignalException.java
public class UnRecitedSpellException extends Exception {
    //エラーメッセージを受け取るコンストラクタ
    public UnRecitedSpellException(String msg) {
        super(msg); //作成したエラーメッセージを親に渡している。
    }
}
```

```Main.java
public class Main {
    public static void main(String[] args){
        try {
            throw new UnRecitedSpellException("呪文が詠唱が間違っているぜ！")
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
```

# List
可変長の配列を使いたいときはリストを使う。

```基本形.java
List<String> list = new ArrayList<>();
```
ArrayListのデータ型はJava7から省略可能。
Listのデータ型も省略可能だが何でも代入できる曖昧なものになってしまうので非推奨。

ArrayListはListを継承している。
Listはインタフェースなのでインスタンスを生成できない。
✖　`List<String> list = new List<>();`

ArrayListにしかないcloneメソッドを使いたいときはArrayListで宣言する。
`ArrayList<String> list = new ArrayList<>();`

```リストの使い方.java
List<String> list = new ArrayList<>();
list.add("a");
list.add("b");
system.iut.println(list.size() + "個ある1つ目の値：" + list.get(0));
```

```初期値を設定する方法.java
List<String> list = new ArrayList<>(Arrays.asList("a","b"));
```
```固定長にする方法.java
List<String> list = Arrays.asList("a","b");
//固定長なのでaddできない
```

# シングルトン
シングルトン（Singleton）パターンは、オブジェクト指向におけるデザインパターンの一つで
「クラスから生成されるインスタンスを1つだけに制限する」
という目的を持っています。
特徴まとめ
・インスタンスは1つだけ
・どこからでもアクセス可能（グローバルアクセス）
・同じオブジェクトを共有して使いたいときに便利

イメージで言えば、
🧑‍💼「会社に社長は1人だけ」
🏠「家にリモコンは1つだけ」
のような感じですね。何個もあったら困るものに向いています。

よく使われる例
シーン	説明
設定クラス■アプリの設定（例：テーマ、言語など）をどこでも共通で参照したいとき
ログ出力クラス■全体で共通のログ機能を持ちたいとき（ログファイルやコンソールに出力）
データベース接続■DBとのコネクションを1つにまとめて管理したいとき（同時接続数を制限）
キャッシュ管理■全体で使うキャッシュデータを一括管理したいとき
セッション管理■ユーザーの状態（ログイン中など）をアプリ全体で把握したいとき

例えばログ機能：

```sample.java
Logger.getInstance().log("ログを出力！");
```
複数のクラスから呼ばれても、すべて同じ Logger インスタンスが動作していて、 同じログファイルや出力先に書き込まれます。

```sample.java
public class SettingsManager {
    // 1つのインスタンスを保持するための静的変数
    private static SettingsManager instance;

    // 設定を保持するための変数（例: 設定名）
    private String setting;

    // プライベートコンストラクタで外部からのインスタンス化を防止
    private SettingsManager() {
        setting = "Default Setting";
    }

    // インスタンスを取得するためのメソッド
    public static SettingsManager getInstance() {
        if (instance == null) {
            instance = new SettingsManager();  // 初回呼び出し時にインスタンスを生成
        }
        return instance;  // 同じインスタンスを返す
    }

    // 設定を取得するメソッド
    public String getSetting() {
        return setting;
    }

    // 設定を更新するメソッド
    public void setSetting(String setting) {
        this.setting = setting;
    }
}
```
コンストラクタをprivateにして外部からのインスタンス化(new)を無効
getInstance()をstaticで呼べるようにしインスタンスが存在しないときだけ生成。

シングルトンを使う理由（メリット）
✅ インスタンスの一貫性	アプリ全体で同じ状態を共有できる
✅ リソース節約	無駄にインスタンスを何個も作らない（メモリ・接続数の節約）
✅ グローバルに使える	どこからでもアクセスできて便利

シングルトンの注意点（デメリット）
❌ テストが難しくなる	状態を共有するため、テスト時に他と干渉しやすい
❌ 再利用性が低くなる	他のアプリや環境で使いにくくなる場合がある
❌ 複雑になりやすい	スレッドセーフにしようとすると実装が複雑になることもある
なので、「どんな場面でも使えばいい」わけではなく、**「インスタンスが1つだけでいい理由があるとき」**にだけ使うのがコツです。