List.of(123, "hoge")の型がこわい。泣きそう。

List.of(123, "hoge")がどんな型になるかを見てみたら、きっとList<Object>になっていて「Objectはどんな値にも対応するんですよー」みたいな説明ができると思っていたら、実際は泣くほど怖い型が出てきた。

`List<Serializable&Comparable<? extends Serializable&Comparable<?>&java.lang.constant.Constable&java.lang.constant.ConstantDesc>&java.lang.constant.Constable&java.lang.constant.ConstantDesc>

という型になっている。

f:id:nowokay:20210624205343p:plain

パッケージ名が邪魔くさいので消してみると

List<Serializable&Comparable<? extends Serializable&Comparable<?>&Constable&ConstantDesc>&Constable&ConstantDesc>

となる。 Genericsは怖いのでComapableのGenericsを消してみるとこんな感じ。

List<Serializable&Comparable&Constable&ConstantDesc>

だいぶ怖くなくなった。

ところで、ConstableとかConstantDescってなんだ?知らない子ですね。

これはJava 12で導入されたConstant APIのインタフェース。
JEP 334: JVM Constants API

Java 11であればこんな感じになる。

jshell> List.of(123, "test")
$1 ==> [123, test]

jshell> /v $1
|    List<Serializable&Comparable<? extends Serializable&Comparable<?>>> $1 = [123, test]

これならわりと怖くない。
ComparableGenericsを取り除くとList<Serializable&Comparable>となって、これなら付き合ってあげていいかなという気持ちになる。こうやってインラインで書ける。

ところでJava 12以降でも、LocalDateなどとの組み合わせであれば怖くない型になる。

jshell> List.of(123, LocalDate.now())
$2 ==> [123, 2021-06-24]

jshell> /v $2
|    List<Serializable&Comparable<? extends Comparable<?>>> $2 = [123, 2021-06-24]

LocalDateにはリテラルがないからConstant Poolに入ることがないのでConstableなどが付かないんだろうか。Comparableの中にSerializableがないのもよい。

あと、Streamとの組み合わせであれば望み通りList<Object>が得れる。

jshell> List.of(123, Stream.of())
$3 ==> [123, java.util.stream.ReferencePipeline$Head@5ef04b5]

jshell> /v $3
|    List<Object> $3 = [123, java.util.stream.ReferencePipeline$Head@5ef04b5]

しかし値がな。