【Java SE 11 Programmer I】個人的メモ：総まとめ

#はじめに
私事だがJava SE11 Silverの試験をもうすぐ受ける。
個人的につまづきやすい部分や、「どういう挙動だっけ？」と
分からなくなるときがあるため備忘録として残す。
細かい説明は割愛

#第1章：簡単なJavaプログラムの作成
##クラスの実行コマンド(-cp)
カレントディレクトリ以外にあるクラスファイルを実行
`java -cp build ex.Main`

##import
`test.b.Sample.class`のクラスパスを`bin/test/b/Sample.class`としたとき、
`test.b.Sample.class`のimport文は…

* import test.b.Sample;
* import test.b.*;

binはクラスファイルの配置場所であり、
配置場所はコンパイル時や実行時にクラスパスで指定するものであり、
インポート宣言で指定するものではない

#第2章：Javaの基本データ型と文字列操作
##a = a * a;

```java
public class Sample {
	public static void main(String[] args) {
		int a = 3;
		a = a * a;
		System.out.println(a); //9
	}
}
```

##varの型推論
###varの型推論はローカル変数にのみ使える
フィールドの宣言やメソッドの引数・戻り値に使うのはNG

```java
public class Sample1{
	private static var num1 = 10; //コンパイルエラー
	public static void main(String[] args) {
		var num2 = 10; //エラーなし		
	}
	private static void method(var num3) { //コンパイルエラー
		var num4 = 10; //エラーなし
	}
}
```

###varの型推論が使えない変数への代入
* var a;
    * 初期化する際に型推論を行うため
* var a = null;
* var a = 1, b = 2;
* var a = {1, 2, 3};
    * int[] a = {1, 2, 3}; <- 変数の型からint配列型のインスタンスを生成している
* ラムダ式: var a = ()->{}; 

###varの型推論が使える意外な例
* var a = new ArrayList<>();
    * a.forEach(b->System.out.println(b)); <-bはObject型となる

##final修飾子は変数宣言と同時に
final修飾子は定数を表すものだが、
変数宣言と同時に値を代入する必要はなさそう
以下のような記述でもエラーは起こらない

```java
class A{
	final int num;
	A(){
		num=10;
	}
}
```

ただし、一度設定した値は変更できないため、
以下のようなコードはダメ

```java
class A{
	final int num;
	A(){
		num=10;
	}
	A(int num2){
		this();
		num = num2; //The final field num may already have been assigned
	}
}
```

#第3章：演算子と判定構造
##charと数値の互換性

```java
public class Sample{
	public static void main(String[] args) {
		char c1 = 65;
		System.out.println(c1); //A
		
		short c2 = (short)'A';
		System.out.println(c2); //65
		
		int n = 100;//(byte, short, longも同様)
		// char c3 = n; //コンパイルエラー

		char c4 = (char)n;
		System.out.println(c4); //d

		double d = 100;
		char c5 = (char)h;
		System.out.println(c5); //d
		
	}
}
```

##整数型・実数型の互換性

```java

public class Sample{
	public static void main(String[] args) {
		byte a1 = 100;
		short a2 = 100;
		int a3 = 100;
		long a4 = 100;
		double b1 = a1;
		double b2 = a2;
		double b3 = a3;
		double b4 = a4;
		float c1 = a1;
		float c2 = a2;
		float c3 = a3;
		float c4 = a4;
		//int a = b1; //コンパイルエラー
               //long b = c1; //コンパイルエラー	
	}
}
```

##後置インクリメント

```java
public class Sample {
	public static void main(String[] args) {
		System.out.println(n()); //0
	}
	
	private static int n() {
		int x=0;
		return x++;
	}
}
```
他にも…

```Java
public class Sample{
	public static void main(String[] args) {
		int num = 10;
		System.out.println(num++ + "," + num); //10,11
	}
}
```

#第4章：制御構造
##到達不可なコードはコンパイルエラー

```Java
public class Sample{
	public static void main(String[] args) {
		for(;;) {
			if(true) {
				continue;
				System.out.println("a"); //Unreachable code
			}
			if(true) {
				break;
				System.out.println("b"); //Unreachable code
			}
		}

	}
}
```

#第5章：配列の操作
##配列の初期化
###OKなもの
* int[] array = new int[]{};
* int[] array; array = new int[]{};

###NGなもの
* int[] array = new int[]; array = {1, 2, 3}; 
    * 初期化子は変数宣言とセットでのみ使える
    * 以下のような記述はOK（インスタンスを再生成するため、最初に確保した要素数の縛りはない）
        * int[] array = new int[3];
        * array = new int[]{1, 2, 3, 4};



##配列は変数宣言時（インスタンス生成時）に初期化される

```java
public class Sample1{
	public static void main(String[] args) {
		int[] array1 = new int[3];
		double[] array2 = new double[3];
		char[] array3 = new char[3];
		boolean[] array4 = new boolean[3];
		String[] array5 = new String[3];
		Integer[] array6 = new Integer[3];
		Double[] array7 = new Double[3];
		for(int i=0;i<3;i++) {
			System.out.print(array1[i]+","+array2[i]+","+array3[i]+","+array4[i]+","+array5[i]+","+array6[i]+","+array7[i]+",");
			System.out.println();
		}
	}
}
//0,0.0, ,false,null,null,null,
//0,0.0, ,false,null,null,null,
//0,0.0, ,false,null,null,null,


```
##配列のコピー（同一性）
###System.arraycopy()
`public static void arraycopy​(Object src, int srcPos, Object dest, int destPos, int length)`

* src:コピー元の配列、
* srcPos：コピー元のどの位置からコピーを開始するか
* dest：コピー先の配列
* destPos：コピー先のどの位置からコピーを開始するか
* length：コピーする要素数

```java
public class Sample1 {
	public static void main(String[] args) {
		char[] array = "Hello".toCharArray();
		char[] array2 = new char[array.length];
		System.arraycopy(array, 0, array2, 0, array.length);
		System.out.println(array2); //Hello
		System.out.println(array == array2); //false
	}
}
```

###clone()：1
配列のコピーをするには、`clone()`や変数の代入を用いる

```java
public class Sample1{
	public static void main(String[] args) {
		int[] arrayA = new int[] {1, 2, 3};
		int[] arrayB = arrayA.clone();
		int[] arrayC = arrayA;
		System.out.println(arrayA == arrayB); //false
		System.out.println(arrayA == arrayC); //true
		System.out.println(arrayB == arrayC); //false
	}
}
```
`clone()`はインスタンスの複製であり、そのインスタンスへの参照値がarrayBに格納されるため、
arrayAとarrayBは異なったインスタンスである。
`arrayC = arrayA`については、arrayCにarrayAインスタンスへの参照値が入るため、
同じインスタンスを共有することになる（同じ参照値である）。よって同一。

###clone()：2

```java
public class Sample1{
	public static void main(String[] args) {
		int[][] arrayA = new int[][] {{1, 2}, {1, 2}, {1, 2, 3}};
		int[][] arrayB = arrayA.clone();
		int[][] arrayC = arrayA;
		System.out.println(arrayA == arrayB); //false
		System.out.println(arrayA == arrayC); //true
		System.out.println(arrayB == arrayC); //false
	}
}
```


#第6章：インスタンスとメソッド
##一見コンストラクタに見えても、戻り値がついていれば普通のメソッド

```java
public class Sample{
	Sample(){ //コンストラクタ
	}
	void Sample(){ //メソッド
	}
	public static void main(String[] args) {
		Sample1 s = new Sample1(); //Sampleコンストラクタが呼び出される
		s.Sample1(); //void Sample()が呼び出される
	}
}
```

##コンストラクタと初期化子

初期化子とは、インスタンスが生成されたタイミングで行われる処理。
処理順はコンストラクタよりも早い。

```java
public class Sample{
	{
		System.out.println("A");
	}
	Sample(){
		System.out.println("B");
	}
	Sample(int num){
		System.out.println("C");
	}
	{
		System.out.println("D");
	}
	public static void main(String[] args) {
		new Sample();
		new Sample(1);
	}
	//A
	//D
	//B
	//A
	//D
	//C
}
```

↓ほかの例

```java
public class Sample1{
	Sample1(){
		this(1);
		System.out.println("A");
	}
	Sample1(int num){
		System.out.println("B");
	}
	{
		System.out.println("C");
	}
	public static void main(String[] args) {
		new Sample1();
	}
	//C
	//B
	//A
}
```
##staticについて
###static初期化子
クラスのロード時に行われる処理

```java
static {
	int num = 10;
}
```

###staticな変数の初期値

```java
public class Sample{
	static int num1;
	static String str1;
	int num2;
	String str2;
	public static void main(String[] args) {
		System.out.println(num1); //0
		System.out.println(str1); //null
		System.out.println(num2); //コンパイルエラー
		System.out.println(str2); //コンパイルエラー
	}
}
```

###staticなメソッドからインスタンス変数へはアクセスできない

```java
public class Sample1
	int n; //インスタンス生成タイミングで0で初期化される
	void a() {
		n++;
	}
	public static void main(String[] args) {
		System.out.println(n); //コンパイルエラー
	}
}
```

#第7章：クラスの継承・インタフェース・抽象クラス

##スーパークラスのメソッド呼び出し注意点
スーパークラスのメソッドをサブクラスで呼び出す際
`super.メソッド名`
で呼び出すが、1つ上のものに対してのみ有効。
例えば、
`super.super.メソッド名`
のような記述はできず、2つ上のクラスのメソッドは呼び出せない。

##共変戻り値
オーバーライドする際、戻り値はスーパークラスと同じものでなければならないが、
サブクラスのものでも可能

```java
class A{
	Object method() {
		return null;
	}
}
class B extends A{
	Number method() {
		byte n = 10;
		return n;
	}
}
class C extends B{
	Integer method() {
		int n = 10;
		return n;
	}
}
```

##スーパークラスのコンストラクタ呼び出しの重複

```java
class SampleA{
	public SampleA(int num){
		System.out.println("A");
	}
}

class SampleB extends SampleA{
	public SampleB(){ //コンパイルエラー
		System.out.println("B");
	}
	public SampleB(int num){
		super(num);
		this(); //コンパイルエラー
	}
}

public class SampleC{
	public static void main(String[] args) {
		new SampleB();
		new SampleB(10);
	}
}

```
new SampleB();のとき
スーパークラスと継承関係にあるため、public SampleB()で暗黙的にsuper()が呼び出されるが、
該当コンストラクタがないためエラー
new SampleB(10);のとき
public SampleB(int num)でsuper(int num)が呼び出した後、
this()でpublic SampleB()・ないしsuper()を呼び出すため、
スーパークラスのコンストラクタを2回呼び出すことになる。
`Constructor call must be the first statement in a constructor`というエラーが示すように、
スーパークラスのコンストラクタは重複した呼び出しはできない。

なお、以下のようにすればエラーは起こらない

```java
class SampleA{
	public SampleA(){ //追加
		System.out.println("A");
	}
	public SampleA(int num){
		System.out.println("A");
	}
}

class SampleB extends SampleA{
	public SampleB(){
		System.out.println("B");
	}
	public SampleB(int num){
		this(); //super()削除　＊このとき、super()は記述されていないがもちろん呼び出されない
	}
}

```
##抽象クラスには具象メソッドのみでもOK

```Java
abstract class A{
	void method() {}
	void method2() {}
}
```

##抽象クラスにおけるアクセス修飾子

```java
public abstract class Sample3 {
	public abstract void method1();
	protected abstract void method2();
	abstract void method3();
	private abstract void method(); //この行のみコンパイルエラー
}
```
抽象クラスはオーバーライド前提のクラスであるため、
同一クラス内からのみアクセス可能であるprivate修飾子を付けることはできない
（オーバーライドは異なるクラスを継承するものである）


##オーバーライドとオーバーロード

```java
class SampleA {
	public void method() {
		System.out.println("A");
	}
}

class SampleB extends SampleA {

	//SampleAのmethod()をオーバーライドしている
	public void method1() {
		System.out.println("B");
	}
	
	//シグニチャが異なるため、オーバーロード
	public void method1(String s) {
		System.out.println("C");
	}
}

public class SampleC extends SampleB {
	public static void main(String[] args) {
		SampleA a = new SampleB();
		
		a.method(); //B
		a.method("hello"); //コンパイルエラー
	}
}
```

##コレクションの修飾子
コレクションに対しても普通に修飾子をつけることができる

```java
private int[] array = new int[3];
public List<String> list = new ArrayList<>();
```


##アクセス修飾子とオーバーライド

```java
class SampleA {
	public void method() {
		System.out.println("A");
	}
	
	public void a() {
		method();
	}
}

class SampleB extends SampleA {
	public void method() {
		System.out.println("B");
	}
	
	public void b() {
		method();
	}
}

public class SampleC {
	public static void main(String[] args) {
		SampleB s = new SampleB();
		s.method(); //B
		s.a(); //B
		s.b(); //B
	}
}
```

SampleAクラスのmethod()のアクセス修飾子をprivateに変えると…

```java
class SampleA {
	private void method() {
		System.out.println("A");
	}
	
	public void a() {
		method();
	}
}

class SampleB extends SampleA {
	public void method() {
		System.out.println("B");
	}
	
	public void b() {
		method();
	}
}

public class SampleC {
	public static void main(String[] args) {
		SampleB s = new SampleB();
		s.method(); //B
		s.a(); //A
		s.b(); //B
	}
}
```
継承において、privateメンバ・コンストラクタは引き継がれないため、
SampleBクラスのmethod()はオーバーライドされず、別のメソッドとして定義されることになる。


##インターフェースの多重継承

```java
interface Sample1 {
	void a();
}

interface Sample2 {
	void b();
}

interface Sample3 extends Sample1, Sample2 {
	void c();
}

public class Sample4 implements Sample3{ 
	@Override
	public void a() { 
	}
	@Override
	public void b() {
	}
	@Override
	public void c() {
	}
}
```
Javaでは原則として多重継承は禁止だが、
インターフェースからインターフェースへの継承に限っては多重継承OK

##スーパークラスのデフォルトメソッドを呼び出す
`スーパーインターフェース.super.メソッド`

```java
interface A{
	default void method() {
		System.out.println("A");
	}
}

interface B extends A{
	default void method() {
		A.super.method();
		System.out.println("B");
	}
}

public class Sample1 implements B{
	public static void main(String[] args) {
		A a = new Sample1();
		a.method(); 
		//A
		//B
	}
}
```

ただし、呼び出せるのは1つ上のデフォルトメソッドのみで、
2つ以上うえのデフォルトメソッドは呼び出せない↓↓

```java
interface A{
	default void method() {
		System.out.println("A");
	}
}

interface B extends A{
	default void method() {
		A.super.method();
		System.out.println("B");
	}
}

class C implements B{
	public void method() {
		A.super.method(); //コンパイルエラー
		System.out.println("B");
	}
}
```

##デフォルトメソッドのオーバーライドの注意点
***java.lang.Object***クラスに定義されているメソッドは
デフォルトメソッドでオーバーライドできない

```java
interface A{
	default String toString() {
		return "A";
	}
}
```

`A default method cannot override a method from java.lang.Object `


##第8章：関数型インターフェース・ラムダ式

メソッド参照

```java
import java.util.List;

class Sample{
	public static void print(Integer num) {
		System.out.println(num);
	}
}

public class Sample1{
	public static void main(String[] args) {
		List<Integer> list = List.of(1, 2, 3);
		list.forEach(Sample::print);
	}
}
//1
//2
//3

```
再利用しない簡単な処理はラムダ式を使うが、
関数型インターフェースの実装に、ラムダ式でなく既存のメソッドを使う場合はメソッド参照を用いる



#第9章：API
##Math.round()
int Math.round(float)
long Math.round(double)
：小数点第一位を四捨五入し、小数点以下を丸める（例：2.5 -> 3, 250.3 -> 250）

##System.arraycopy();

##日付関係
###DateTimeFormatter
【DateTimeFormatterクラスの定数の例】
| フォーマッター | 例 |
|:-:|:-:|
| BASIC_ISO_DATE  | 20210515  |
| ISO_DATE  |  2021-05-15 |
| ISO_DATE_TIME  |  2021-05-15T00:00:00 |


```java
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;

public class Sample1 {
	public static void main(String[] args) {
		LocalDateTime time = LocalDateTime.of(2021, 5, 15, 0, 0);
		String str = time.format(DateTimeFormatter.ISO_DATE_TIME);
		System.out.println(str); //2021-05-15T00:00:00
	}
}
```

###Duration
`Duration d = Duration.between(start, end)`
時刻の差を扱う

###Period
`Period p = Period.between(start, end)`
`Period p = localDate.until(target)`
日付の差を扱う


##List<>
###add()：注意点
`add(int index, String element)`で指定した位置に要素を挿入することができるが、
範囲外に挿入しようとすると例外が発生する。

```java
public class Sample1{
	public static void main(String[] args) {
		List<String> list = new ArrayList<>();
		list.add("a");
		list.add(2, "B");
		list.add("c");
		list.add("d");
		System.out.println(list);
	}
	//例外：Exception in thread "main" java.lang.IndexOutOfBoundsException: Index: 2, Size: 1
}
```

###contains()
`boolean contains​(Object o)`

```java
import java.util.List;

public class Sample1 {
	public static void main(String[] args) {
		List<String> list = List.of("a", "b", "c");
		System.out.println(list.contains("b")); //true
		System.out.println(list.contains("x")); //false
	}
}
```

###ラムダ式関連
###forEach()
`void forEach​(Consumer<? super T> action)`

```java
import java.util.List;

public class Sample1 {
	public static void main(String[] args) {
		List<String> list = List.of("a", "b", "c");
		list.forEach(s -> System.out.println(s));
	}
}
//a
//b
//c
```

###removeIf()
`public boolean removeIf​(Predicate<? super E> filter)`

```java
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

public class Sample1 {
	public static void main(String[] args) {
		List<String> list = new ArrayList<>(
				Arrays.asList(new String[] { "a", "b", "c" })
				);
		if(list.removeIf(s -> s.equals("b"))) {
			System.out.println(list);
		}
	}
}
```

###sort()
`void sort​(Comparator<? super E> c)`

```java
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

public class Sample1 {
	public static void main(String[] args) {
		List<String> list = new ArrayList<>(
				Arrays.asList(new String[] { "c", "a", "b" }));
		list.sort((s1, s2) -> s1.compareTo(s2));
		System.out.println(list); //[a, b, c]
		list.sort((s1, s2) -> -s1.compareTo(s2));
		System.out.println(list); //[c, b, a]
	}
}
```



#第10章：例外処理
##エラー・例外の簡単な分類

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/503230/4c94af12-178a-87d8-f3f2-7847e3689bf7.png)

##throws宣言について
throws宣言はあくまで、
「この例外・エラー（またはそのサブクラス）を投げる可能性がありますよ～」
という意味なので、非検査例外であれば、呼び出し元のメソッドで対処する必要はない

```java
public class Sample1
	public static void main(String[] args) {
		try {
			method(0);
		}catch(IOException e) {
		}
	}
	private static void method(int num) throws IOException, IndexOutOfBoundsException {
		if(num==10)throw new FileNotFoundException();
		else throw new IndexOutOfBoundsException();
	}
}
```
* IOExceptin()->検査例外
* IndexOutOfBoundsException()->非検査例外

なお、実際には`FileNotFoundException()`をthrowしているが、
前述したように`throws IOException`と宣言しているため、IOExceptionをcatchする必要あり

##ClassCastException()
* 非検査例外
* インスタンスの型変換ができなかったときに発生
* プリミティブ型(int, char, doubleなど)の型キャストでは発生しない

##UnsupportedOperationException()
* 非検査例外
* 要求されたオペレーションがサポートされていないことを示す
* List.of()などで生成した固定のリストを変更（追加や削除）しようとしたら発生する

##ExceptionInInitializerError()
* エラー
* staticイニシャライザ内で問題が発生したときに起こるエラー

#第11章：モジュールシステム
##コマンドラインからの操作
###`java --list-modules`
現在の実行環境で参照可能なモジュールの取得

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/503230/c796bf84-0231-23b2-317c-3ec6729b491b.png)

###コンパイル
`javac -d <クラスの生成位置> <コンパイルするファイル>`
`javac -d out foo\XTest.java`
-d クラスの生成位置の指定

`--module-path <モジュールのルートディレクトリ>`
`javac -d out --module-path out src\module-info.java src\app\Main.java`
--module-path（または-p）アプリケーション・モジュールを検索する位置の指定

###実行
`java --module-path out\foo;out\client --module client/app.Main`
--module（または-m）モジュール名とエントリポイントとなるクラスの指定

###モジュールの設定情報を調べるためのコマンド
`java --module-path out --describe-module foo`
--describe-module
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/503230/f0d3218a-c6e1-94da-a070-4d80ffe4f1a5.png)

jmod describe


###クラス・メソッド・モジュールの依存関係を調べるコマンド
* `jdeps --list-deps out\foo`
* `java --show-module-resolution`

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/503230/4bf77b8f-0c6a-fdbf-1602-f6a71a76ca76.png)



#おわりに
黒本のコードや解説を参考にまとめています

https://www.amazon.co.jp/%E5%BE%B9%E5%BA%95%E6%94%BB%E7%95%A5Java-SE-11-Silver%E5%95%8F%E9%A1%8C%E9%9B%86-1Z0-815/dp/4295007625/ref=sr_1_1?__mk_ja_JP=%E3%82%AB%E3%82%BF%E3%82%AB%E3%83%8A&crid=3OOLNJWN6WSJX&dchild=1&keywords=java+silver+%E9%BB%92%E6%9C%AC&qid=1621672327&sprefix=Javasilver%2Caps%2C278&sr=8-1

【結果】
無事合格できました。
受けた感想としては、黒本やってて良かったなーという感じです笑
黒本の末章には総まとめ問題が2つありますが、
似たような問題が多かったです。
何なら全く同じ問題もいくつかあった気がするので、
黒本の総まとめ問題をやっていれば2,3割ぐらいはサービス問題ですね。

とりあえず1週間ぐらいはゆっくり過ごして、
その後はまたJava関連の勉強をしようかな～という感じにしたいと思います。