Лично я с тобой полностью согласен.В основе проблемы лежит тот факт, что дженерики Java не являются ковариантными, что, в свою очередь, связано с изменчивостью коллекций Java.
Система типов Java не может кодифицировать тип, который, по-видимому, имеет мутаторы , которые фактически неизменны .Представьте себе, если бы мы начали разработку какого-то решения:
interface Immutable //marker for immutability
interface ImmutableMap<K, V> extends Map<K, V>, Immutable
Но тогда ImmutableMap
является подклассом Map
, и, следовательно, Map
можно назначить из ImmutableMap
, поэтому любой метод, который возвращает такойнеизменяемая карта:
public ImmutableMap<K, V> foo();
может быть назначена карте и, следовательно, может быть видоизменена во время компиляции:
Map<K, V> m = foo();
m.put(k, v); //oh dear
Итак, вы можете видеть, что добавление этого типа на самом деле не имеетпомешал нам сделать что-нибудь плохое.Я думаю, что по этой причине было принято решение, что у него недостаточно предложений.
Язык, подобный scala , имеет аннотации на сайте объявлений.То есть, вы можете указать тип как ковариантный (и, следовательно, неизменный), как это делает карта Scala (на самом деле он ковариантен в своем параметре V
).Следовательно, ваш API может объявить, является ли его возвращаемый тип изменяемым или неизменным.
В качестве еще одного отступления Scala позволяет объявлять типы пересечений, так что вам даже не нужно создавать интерфейс ImmutableXYZ
как отдельную сущность,Вы можете указать метод для возврата:
def foo : XYZ with Immutable
Но тогда у Scala есть правильная система типов, тогда как у Java нет