わたしがJavaの嫌なところ５選

# Java

昨年、20周年を迎えたJava。
最近は関数型言語が流行ってきたり、Script系言語でサッとつくることが多くなってきたので、使ってる人は、昔に比べると減ったのかなと思いますが、それでも、多いですよね。
20周年のイベントもたくさんあったりしました。
そんなJavaですが、まだまだ発展中です。「嫌い」という声も聞いたりします。
私が個人的に「嫌なところ」を書いてみたいと思います。

## プリミティブ型が中途半端

プリミティブ型(int,long等)とそれを表現するクラス(java.lang.Integer, java.lang.Long等)の両方があるため、どちらを使おうか迷ったりします。また、その影響で混乱することがあります。
例えば、

 - int型
 - Integerクラス

がありますね。
IntegerクラスはImmutableなので、単純にIntegerクラスだけでいいとかいうわけではありませんが、いろいろ混乱します。
代表的なのはこんな例

```lang:java
public class IntegerSample {
  static public void main(String[] args){
    System. out.println("new Integer(100)" );
    Integer new100_1 = new Integer(100);
    Integer new100_2 = new Integer(100);
    System. out.println("  ==  :" + (new100_1 == new100_2 ));
    System. out.println("equals:" + new100_1 .equals(new100_2 ));
  }
}
```

これを実行すると


> new Integer(100)
>   ==  :false
> equals:true

ふむふむ。オブジェクトを==で比較してるので、こっちはfalseになるね。
じゃあ、少し変えて、こんなふうに。

```lang:java
public class IntegerSample {
  static public void main(String[] args){
    System. out.println("Integer.valueOf(100)" );
    Integer valueOf100_1 = Integer.valueOf(100);
    Integer valueOf100_2 = Integer.valueOf(100);
    System. out.println("  ==  :" + (valueOf100_1 == valueOf100_2 ));
    System. out.println("equals:" + valueOf100_1 .equals(valueOf100_2 ));
  }
}
```

Integerのオブジェクトをnewじゃなくて、Integer.valueOf()で取得するように変えました。
これを実行すると、

> Integer.valueOf(100)
>   ==  :true
> equals:true

あれ？trueだ。
ふーん、valueOfで取得すると、同じインスタンスになるのかー。ほんとかなー。確かめてみよう。
今度は、

```lang:java
public class IntegerSample {
  static public void main(String[] args){
    System. out.println("Integer.valueOf(1000)" );
    Integer valueOf1000_1 = Integer.valueOf(1000);
    Integer valueOf1000_2 = Integer.valueOf(1000);
    System. out.println("  ==  :" + (valueOf1000_1 == valueOf1000_2 ));
    System. out.println("equals:" + valueOf1000_1 .equals(valueOf1000_2 ));
  }
}
```

数字を100じゃなくて、1000にしてみた。
実行すると、

> Integer.valueOf(1000)
>   ==  :false
> equals:true

おー、今度はfalseだ。なんだこれ？？
となったので、ソースコードを確認してみました。
すると、Integerクラスの中には、IntegerCacheという内部クラスがあり、-128～127までのIntegerクラスのオブジェクトがキャッシュされているではありませんか！
Integer.valueOf()で取得したときに、-128～127は同じインスタンスが返されて、それ以外の場合は別のインスタンスが返されています。
実は、Byteクラス、Shortクラス、Longクラスも同じように-128～127はXxxCacheという名前の内部クラスがあり、キャッシュされているのです！
もちろん、==じゃなくて、euqals()で比較するんだってはなしですが。このような実装になっていると、バグを発見しづらいことがあります。
※ただ、これは、「Javaの嫌なところ」じゃなくて、「Oracle Javaの嫌な実装」なんですけどね。
※この前、このバグを発見できなくて、悔しかったです。
※operatorのオーバーライドがあればなーと久しぶりに思いました。


## 日時のクラス群がカオス

最初からある、java.util.Dateクラス、JDK1.1で追加されたjava.util.Calendarクラス、そして、Java8で新たに導入されたjava.timeパッケージの仲間たち。
なかなかカオスです。
java.timeパッケージは新しい日時表現のクラス群として、登場してきました。java.util.Dateクラス、java.util.Calendarクラスの良くないところを改善して、導入されました(joda-timeという、日時を扱うライブラリをベースに導入されたようです)。
なので、こちらを使うことを推奨されていくと思います。
ただし、まだ導入するメリットはなかなか味わえないかなと感じています。
単純に時間を扱うだけであれば、java.timeパッケージを使った実装をすればよいですが、既存のライブラリやフレームワークを使う際には、java.timeパッケージに対応していなければ、せっかくjava.timeパッケージを使って実装していても、ライブラリやフレームワークとのやり取りの部分で変換しなければ使えません。
例えば、DBと日時のデータをやり取りする場合は、java.util.Data(たぶん、java.sql.Dateだったりしますが)と変換してあげなければなりません。めんどくさいですね。そして、せっかくjava.timeパッケージで処理してるのに、、、と思ってしまいます。
もう少し時間が経過して、java.timeパッケージが少し広まったとき、このライブラリはjava.timeパッケージで実装できるけど、こっちはjava.util.Dateだから、、、うーーん。。。ってなりそうです。

## Stop The World

時間が止まります。
FullGCのときに。
まあ、それ自体は諦めてます。仕方ないと思ってます。
つらいのはStop The Worldが原因の問題が出るとき。対処方法が難しいのです。
Heapサイズを変えるとか、EdenとOldとサイズをチューニングするとか。GCのアルゴリズムを変えてみるとか。いろいろいろいろ。
これ！って対応方法を見つけるのがすごく難しいんですよね。

## getter/setterをそろそろなんとかしてほしい

ずーーっと言われてますね。
最近はlombokがよく使われますが、それでもアノテーションを付けなければならないです。
このあたりの話をするとpublicでいいじゃないかとか論争がはじまることがよくあって、もーってなります。
※フレームワークがgetter/setterを要求することがおおいので、「publicでいいじゃないか論」はちょっと違うんじゃないかと思ってます。
そろそろ、アクセス修飾子の代わりにpropertyつければgetter/setterができるようになってほしいなぁと思うわけです。もちろん、getterだけ/setterだけができる修飾子もほしいです！

## 「JAVA」って書かれる

いや、別に、いいんですけど。
なんか、気持ち悪くて。
でも、公式も「あなたとJAVA」( https://www.java.com/ja/ )なんだよなぁ。
※公式はここ以外"JAVA"という表記見たことがない気がしますが、あるのかな？

# まとめ

**Java大好きです！**
最初から「嫌い」なんて言ってないですよ。「嫌なところ」です。
今後とも、よろしくお願いします。Javaさん！ :smile: