個人的にはあなたに完全に同意します。問題の中心にあるのは、Java のジェネリックが共変ではないという事実です。これは、Java のコレクションが変更可能であるためです。
Java の型システムでは、 mutatorsが実際には immutableであると思われる型を成文化することはできません。ソリューションの設計を開始する場合を想像してください。
interface Immutable //marker for immutability
interface ImmutableMap<K, V> extends Map<K, V>, Immutable
しかし、ImmutableMap
は のサブクラスであるMap
ため、そのような不変の Map を返す任意のメソッドMap
から割り当てることができます。ImmutableMap
public ImmutableMap<K, V> foo();
Map に割り当てることができるため、コンパイル時に変更できます。
Map<K, V> m = foo();
m.put(k, v); //oh dear
したがって、この型を追加しても、実際には何も悪いことを防げていないことがわかります。そのため、十分に提供できないという判断が下されたと思います。
scalaのような言語には、宣言サイトの差異に関する注釈があります。つまり、Scala の Map のように型を共変 (したがって不変) として指定することができます (実際にはそのV
パラメーターで共変です)。したがって、API は戻り値の型が可変か不変かを宣言できます。
余談ですが、Scala では交差タイプを宣言できるため、ImmutableXYZ
インターフェイスを別のエンティティとして作成する必要さえありません。返すメソッドを指定できます。
def foo : XYZ with Immutable
しかし、scala には適切な型システムがありますが、Java にはありません。