思わず頭にきたのでメモ書き。
あるメソッドがあります。このメソッドは int
を受け取っていました。
ある時、このメソッドが Integer
を受け取るように改修が入りました。他はどこも Integer
を使っていたからです。
引数の型を書き換えたところ、そのメソッドはコンパイルエラーの一つも出さずに受け入れました。
もうわかるな。NullPointerException
だ。
なにがあったの
Integer.valueOf(int)
が使われていた。
引数はInteger.valueOf(int)
へ流し込まれるにあたり、まず Auto Boxing による変換が挟まり、つまり Integer.valueOf(Integer.intValue())
となった。
Integer
は primitive ではないので null
になりうる。
null
に対してメソッド呼び出しをかけようとすれば当然 NPE で落ちる。
そして Integer
と int
は Auto Boxing で暗黙に相互変換されるため、コンパイラはエラーを吐かない。
Javaなんて嫌いだ。
どうすればいいの
Wrapper Class を使うな。古事記 Effective Java にもそう書いてある。
そもそも Wrapper Class という連中はひどくクソッタレな仕様をしている。そもそもラップされている primitive たちと特性を合わせる気がさらさらないのだから笑うしかない。
primitive は mutable なのに Wrapper Class は immutable (しかもそれらを暗黙に相互変換だって? 冗談じゃない。int
とInteger
をそれぞれインクリメントして調べてみるといい!) ってどういうことだ。
(fix: ややこしいがmutableではなかったので訂正。インクリメントの挙動違いはスタック周り、って最近そういう話がよく出るなあ……)
しかし、現実には Wrapper Class でないと Generics 周りでめんどくさい思いをするハメになる。
特に Optional が使えないのは致命的だ。
仕様上どうしようもないのはわかるが、それはそれとして正直……
Wrapper Class どもに Optional を直接実装してくれりゃあ使い物になったろうにと今でも思う (やれるならやったんだろうが) 。
(もちろん Optional なら OptionalInt がある。が、まとめて扱えないのはやはり欠陥だと思う)
だから、もう一度いう。Wrapper Class を使うな。
そして、Wrapper Class が出てきてしまったなら、そいつは Optional だと思え。