enumの比較は==がつよつよ、equalsはよわよわ【Java】

# 理由

- [==はNullPointerExceptionが発生しない/ equalsは発生する](#はnullpointerexceptionが発生しない-equalsは発生する)
- [==は型変換がないため無駄がない（速い）/ equalsはObject型への型変換があるため無駄がある（遅い）](#は型変換がないため無駄がない速い-equalsはobject型への型変換があるため無駄がある遅い)
- [==はコンパイル時に型チェックがある/ equalsは型チェックない](#はコンパイル時に型チェックがある-equalsは型チェックない)

## ==はNullPointerExceptionが発生しない/ equalsは発生する

```java:ぬるぽ確認
public class EnumNullPointerExceptionTest {

	enum Season { SPRING, SUMMER, AUTUMN, WINTER; }

	public static void main(String[] args) {
		Season season = null;
		if (season != Season.SPRING) {
			System.out.println("季節は春ではありません。");
		}

		if (!season.equals(Season.SPRING)) {
			System.out.println("季節は春ではありません。");
		}
	}
}
```
```:実行結果
季節は春ではありません。
Exception in thread "main" java.lang.NullPointerException
	at EnumNullPointerExceptionTest.main(EnumNullPointerExceptionTest.java:13)
```
==は通って、equlasでぬるぽで怒られた（実際に通ったのは、!=だけども）。

NullPointerExceptionが発生しない==つよつよ:blush:
NullPointerExceptionが発生しちゃうequlasよわよわ:sweat:
## ==は型変換がないため無駄がない（速い）/ equalsはObject型への型変換があるため無駄がある（遅い）
```java:==の処理時間計測
public class EnumSpeedTest1 {

	enum Season { SPRING, SUMMER, AUTUMN, WINTER; }

	public static void main(String[] args) {
		Season season = Season.SPRING;

		long startTimeMs = System.currentTimeMillis();
		for (int i = 0; i < 2000000000; i++) {
			if (season == Season.SPRING) {}
		}
		long executionTimeMs = System.currentTimeMillis() - startTimeMs;
		System.out.println("比較を20億回繰り返すのにかかった時間は" + executionTimeMs + "ミリ秒です");
	}
}
```
```:==の実行結果
比較を20億回繰り返すのにかかった時間は2ミリ秒です
```
```java:equlasの処理時間計測
public class EnumSpeedTest2 {

	enum Season { SPRING, SUMMER, AUTUMN, WINTER; }

	public static void main(String[] args) {
		Season season = Season.SPRING;

		long startTimeMs = System.currentTimeMillis();
		for (int i = 0; i < 2000000000; i++) {
			if (season.equals(Season.SPRING)) {}
		}
		long executionTimeMs = System.currentTimeMillis() - startTimeMs;
		System.out.println("比較を20億回繰り返すのにかかった時間は" + executionTimeMs + "ミリ秒です");
	}
}
```
```:equalsの実行結果
比較を20億回繰り返すのにかかった時間は4ミリ秒です
```

わずかだけど、==の方は型変換しないから速いね。

型変換がなくて無駄がない==つよつよ:relaxed:
型変換が必要で無駄があるequalsよわよわ:sweat:
## ==はコンパイル時に型チェックがある/ equalsは型チェックない
```java:コンパイル確認
public class EnumCompileTest {

	enum Season { SPRING, SUMMER, AUTUMN, WINTER; }
	enum Color { RED, GREEN, BLUE; }
	enum Animal { DOG, CAT; }

	public static void main(String[] args) {
		if (Season.SPRING.equals(Color.RED)) {}
		if (Season.SPRING == Animal.CAT) {}
	}
}
```
```:コンパイル結果
$ javac EnumCompileTest.java
EnumCompileTest.java:10: エラー: 型SeasonとAnimalは比較できません
		if (Season.SPRING == Animal.CAT) {}
		                  ^
エラー1個
```
型が違う==の比較は怒られた。

コンパイル時に型チェックがある==つよつよ:relaxed:
コンパイル時に型チェックないequalsよわよわ:sweat:

# 番外:なぜenumは==で比較できるのか？
言語仕様には、こう書いてあるよ。
[8.9.1. Enum Constants](https://docs.oracle.com/javase/specs/jls/se9/html/jls-8.html#jls-8.9.1)
> Because there is only one instance of each enum constant, it is permitted to use the == operator in place of the equals method when comparing two object references if it is known that at least one of them refers to an enum constant.

there is only one instance of each enum constantってことは、
enumのインスタンスはシングルトンなんだね。だから、==で比較できると。

# 参考
- [The Java® Language Specification
Java SE 14 Edition 8.9. Enum Types](https://docs.oracle.com/javase/specs/jls/se14/html/jls-8.html#jls-8.9)
- [Stack Overflow: Comparing Java enum members: == or equals()?](https://stackoverflow.com/questions/1750435/comparing-java-enum-members-or-equals)
- [enum の比較は安心して == を使ってください](https://blog1.mammb.com/entry/2013/10/03/092927)
- [[java] Enum の「equals」vs「==」(右の勝ち)](https://qiita.com/hcl/items/8e554df74332a6b79bcc)