[java] Java SE 8 Silver メモ


## 試験の心得
- 設問をよく読むこと（正しい、誤りを、3個などは見落とさない）
- 変数の型、アクセス修飾子は注意深く確認すること
  型の不一致やアクセス権限の問題に要注意

## java の基本
- 無名パッケージに属するクラスは無名パッケージに属するパッケージからしかアクセスできない  
  protected は別パッケージのクラスで継承された時、継承したクラスからアクセスできるが、無名パッケージはアクセス不可(無名パッケージの制約が優先)
- パッケージに階層の概念はない

## java のデータ型の操作
- リテラルにアンダーバー(_)が使用できる(以下の制限あり)
  - リテラルの先頭と末尾に記述できない(NG: _0)
  - 記号の前後に使用できない(NG: 0_.0)
- 小数点リテラルのデフォルトは double  
  このため、float の変数にリテラルを代入する場合は、型(接尾子)を指定する必要がある
  
  ```java
  float f = 0.0f;
  ```
  
- 変数、メソッド、クラスなどの名前（識別子）は以下の制限がある
  - 予約語は使えない
  - 使える記号は、アンダーバー(_)、通貨記号($等)のみ
  - 数字から始めてはいけない
- byte 型は 8ビット整数(-128か〜127)


  ```java
  byte b = 0b1000000;
  →128 のためエラー
  byte b = (byte)0b1000000;
  →-128 のためOK
  ```
  
- 上位の型(int であれば long)への代入はキャスト不要(アップキャスト)


  ```java
  int a = 1;
  long b = a;

  float f = 0.0f;
  double d = f;
  ```
  
- 下位の型への代入はキャストが必要(ダウンキャスト)


  ```java
  long a = 1;
  int b = (int)a;

  double d = 0.0;
  float f = (float)d;
  ```

- クラスに関しても同じルール

## 演算子と判断構造の使用
- equal メソッドは Object クラスで定義され、インスタンスチェック(同一性チェック)
- String クラスの equal メソッドは、文字列チェック（同値性チェック）
- equal メソッドをオーバライドした問題がでた場合、上記を意識すること
- 文字列リテラルはコンスタントプールに配置され、同じリテラルは共有されるため、以下の条件は true となる

  ```java
  String a = "aaa"
  String b = "aaa"
  System.out.println(a == b);
  → true が表示される
  ```
  
- if 文で処理を改行して書くとコンパイラは中括弧を適宜付与する(ひっかけに注意)


  ```java
  int num = 10;
  if (num == 100)
    System.out.println("A");
  else if (num > 10)
    System.out.println("B");
  else
  if (num == 10)
    System.out.println("C");
  else
  if (num == 10)
    System.out.println("D");

  ```
  
  コンパイラの解釈
  
  ```java
  int num = 10;
  if (num == 100) {
    System.out.println("A");
  } else if (num > 10) {
    System.out.println("B");
  } else {
    if (num == 10) {
      System.out.println("C");
    } else {
      if (num == 10) {
        System.out.println("D");
      }
    }
  }

  ```
  
- switch 文に条件が渡せる型に long, boolean は含まれない!
- switch の条件に変数は使えない


## 配列の作成と使用
- 配列の型宣言で要素数は指定しない（コンパイルエラー）


  ```java
  // 基本形
  int [] a;
  // これだめ
  int [3] a;
  ```

- 配列の初期化で要素数と初期値設定を同時にかけない（コンパイルエラー）

  ```java
  // 基本形
  int [] a = new int []{1, 2};
  // これだめ
  int [] a = new int [2]{1, 2};
  ```

- 配列の宣言と初期値設定を別にかけない（コンパイルエラー）

  ```java
  // 基本形
  int [] a = new int []{1, 2};
  // これだめ
  int [] a;
  a = {1, 2};
  ```


## ループ構造の使用
- 特に注意点無し

## メソッドとカプセル化の操作
- 可変長引数宣言
  - 以下のように定義する

  ```java
  void sample(int... num) {
    for (int i = 0; i < num.length; i++) {
      System.out.println(num[i]);
    }
  }
  ```

  - 可変長引数は配列として渡される
  - 可変長引数は最後にだけ指定可能


  ```java
  void sampl(int... num, int pos) {
  →エラー
  }
  ```

- アクセス修飾子のアクセス強度
  - public: すべてのクラスからアクセス可能
  - protected: 同じパッケージに属するか、継承しているサブクラスからのみアクセス可能
  - 修飾子なし: 同じパッケージに属するクラスからアクセス可能
  - private: クラス内からのみアクセス可能
  - 注意: 無名パッケージに属するクラスは同じ無名パッケージに属するクラスからしかアクセスできない
- 継承したメソッドの修飾子は元の修飾子と同じか、それうよりもゆるい修飾子をつける
  (ex: protected: protected or public)
- インターフェースの抽象メソッドはアクセス修飾子は"public"
- static で修飾されたメソッドからは、static で修飾されたもの以外にはアクセスできない

  ```java
  public class Main {
    int num;
    private static void test() {
      num++;
      →コンパイルエラー
      System.out.ptintln(num)
    }
  ```

- 暗黙の型変換によりコンパイルエラー「あいまいなメソッドの呼び出し」が発生する

  ```java
  public class Main {
    public static void main(String [] args) {
      Main m = new Main();
      System.out.println(m.calc(2, 3));
      →2, 3 は暗黙の型変換により、double にも解釈できるこのため、
        オーバロードされたどちらのメソッドを呼び出すか判断できない。。。
        →「あいまいなメソッド呼び出し」にてコンパイルエラー
    }

    private double calc(double a, int b) {
      return (a + b) / 2;
    }

    private duoble calc(int ak double b) {
      return (a + b) / 2;
    }
  }
  ```

- コンストラクターの呼び出し(super, this)は処理の最初に行わなければならない

  ```java
  public class Main {
    public Main() {
      System.out.println("A");
      this("B");
      →コンパイルエラ
    }
    public Main(String str) {
      System.out.println("B");
    }
  
    public static void main(String [] args) {
      Main m = new Main();
    }
  }
  ```

- protected は、継承されたクラス内で参照できる（が、インスタンスのメソッドとしては呼び出せない）  
  当然ですが、勘違いしそうなので

  ```java
  package other;
  
  public class Book {
    private String isbn;
    public void setIsbn(String isbn) {
      this.isbn = isbn;
    }
    protected void printInfo() {
      System.out.println(this.isbn);
    }
  }
  ```

  ```java
  package pkg;
  import other.Book;
  
  public class StoryBook extends Book {}
  ```

  ```java
  package pkg;
  
  public class Main {
    public static void main(String [] args) {
      StoryBook sb = new StoryBook();
      sb.setIsbn("xxxx-xxxx-xxxx");
      sb.printInfo();
      →コンパイルエラー
    }
  }
  ```

## 継承の操作
- サブクラスは、コンストラクタ、private なフィールドやメソッドは引き継がない
- 継承のルール
  - クラス同士は単一継承のみ
  - インターフェース同士は多重継承が可能
- ポリモフィズムは、継承関係にあるクラスだけでなく、インタフェースと実装の関係でもなりたつ

  ```java
  interface Worker() {
    void work();
  }
  
  class Employee {
    public void work() {
      System.out.println("work");
    }
  }
  
  class Engineer extend Employee implements Worker { }
  
  public class Main {
    public static void main(String [] args) {
      Worker w = new Engineer();
      →work が出力される（コンパイルエラーは発生しない）
    }
  }
  ```

## 例外の処理
- 例外クラスは、大きく分けて ErrorとException、RuntimeException に分かれる
  - Error: プログラムからは回復不能なエラー(OutOfMemoryError, StackOverflowError, NoClassDefFoundError 等)
    →検査しても回復不能
  - 検査例外: Exception およびそのサブクラス
  - 非検査例外: プログラムミスにうよるエラー(RuntimeException およびそのサブクラス. NullPoiterException 等)
- 検査例外は例外の対応処理をしなければならない(try-catch か throws句宣言を強要される)
- static イニシャライザを処理している場合にトラブルが発生した時には、通知相手がいないため、JVMは ExceptionInitializerError を発生させ、プログラムを強制終了する
  
  ```java
  public class Main {
    private static String name;
    static {
      if (name.length() == 0) {
      →name が初期化されていない状態で length() を呼び出したため、エラーが発生する
        name = "sample"
      }
      public static void main(String[] args){
        System.out.println("hellow " + name);
      }
  }
  ```
  
- 2重 try-catch-finally について finally 節はかならず実行される
  
  ```java
  public class Main() {
    public static void main(String[] args) {
      try {
        try {
          String[] array= {"a", "b", "c"};
          System.out.println(array[3]);
        } catch (ArrayIndexOuntOfBoundsException e) {
          System.out.println("D");
        } finally {
          System.out.println("E");
          →実行される
        }
      } catch (ArrayIndexOutOfBoundsException e) {
        System.out.println("F");
      } finally {
        System.out.println("G");
        →実行される
      }
    }
  }
  →"D E G"が表示される
  ```

  ```java
  public class Main() {
    public static void main(String[] args) {
      System.out.println(test(null));
      →A を表示
    }
    private static String test(Object obj) {
      try {
        System.out.println(obj.toString());
      } catch (NullPointerException e) {
        return "A";
        →A がスタックに積まれる
      } finally {
        System.out.println("B");
        → return 前に B を出力
      }
    }
  }
  →"B A" が表示される
  ```

## java API の主要なクラス操作
- String object の生成方法
  
  ```java
  String a = new String("sampl");
  String b = "sample"
  String c = String.valueOf("sample");
  ```
  
- null が代入された String オブジェクトを連結(+)すると"null"と変換されて連結される
  
  ```java
  String a = null;
  a += "null";
  System.out.println(a)
  →"nullnull"と表示される
  ```
  
- StringBulider は内部的にデータを char[] で管理し、デフォルトで 16文字分のバッファを持つ
  
  ```java
  StringBuilder sb = new StringBuilder("abcde");
  System.out.println(sb.capacity());
  →21 が出よくされる(バッファ16文字+5)
  ```
  
- ラムダ式の構文に関して
  - ラムダ式で中カッコを省略した場合、処理は一文で記述できる。この時、return は記述できない
  - ラムダ式で中カッコを記述した場合、return は省略できない
    
    ```java
    Function f = str -> "hello " + str;
    Function f = str -> { return "hello " + str };
    ```
    
- ラムダのメソッド内で宣言したローカル変数と同じ名前の変数をラムダ式の変数に使うことはできない
  
  ```java
  public class Main {
    public static void main(String[] args) {
      String val = "A";
      Function f = (val) -> { System.out.println(val); };
      →コンパイルエラー
    }
    interface Function { void test(String val); }
    →関数型インターフェース
  }
  ```

- ラムダ式の外で宣言されたローカル変数にラムダ式からアクセスするには、実質的に final な変数でなければならない（そうでない場合、コンパイルエラー）
  
  ```java
  public class Sample {
    public static void main(String[] args) {
      int cnt = 0;
      Runnable r = () -> {
        for (cnt = 0;  cnt < 10; i++) {
          →コンパイルエラー(final でない。。。)
          System.out.println(cnt++);
        }
      }
      new Thread(r).start();
    }
  }
  ```

- StringBuilder の equals メソッドは object の比較(値比較は行わない)
- LocalDate, LocalDateTime クラスのコンストラクタでありえな日付を指定すると例外が throw される
- LocalData, LocalDateTime クラスは immutable(内部データは更新されない)