Какая разница между Collections.unmodifiableSet() и ImmutableSet от Guava?
JavaDoc ImmutableSet
говорит:
В отличие от Collections.unmodifiableSet
, который является видом отдельной коллекции, которая все еще может измениться, экземпляр этого класса содержит свои личные данные и никогда не изменится. Этот класс удобен для публичных статических окончательных наборов ( "постоянные наборы" ), а также позволяет легко сделать "защитную копию" набора, предоставленного вашему классу вызывающим.
Но ImmutableSet
по-прежнему сохраняет ссылку на элементы, я не мог понять разницу в Collections.unmodifiableSet()
. Пример:
StringBuffer s=new StringBuffer("a");
ImmutableSet<StringBuffer> set= ImmutableSet.of(s);
s.append("b");//s is "ab", s is still changed here!
Может ли кто-нибудь объяснить это?
Ответы
Ответ 1
Рассмотрим это:
Set<String> x = new HashSet<String>();
x.add("foo");
ImmutableSet<String> guava = ImmutableSet.copyOf(x);
Set<String> builtIn = Collections.unmodifiableSet(x);
x.add("bar");
System.out.println(guava.size()); // Prints 1
System.out.println(builtIn.size()); // Prints 2
Другими словами, ImmutableSet
неизменен, несмотря на то, что сборник, который он создал из потенциально изменяющегося, - потому что он создает копию. Collections.unmodifiableSet
предотвращает прямое изменение возвращенной коллекции, но она все еще является представлением о потенциально изменяющемся наборе поддержки.
Обратите внимание, что если вы начнете изменять содержимое объектов, на которые ссылается любой набор, все ставки все равно. Не делай этого. В самом деле, редко возникает идея создать набор с использованием типа изменяемого элемента в первую очередь. (Ditto карты с использованием изменяемого типа ключа.)
Ответ 2
Помимо различий в поведении, которые упоминает Джон, важным отличием между ImmutableSet
и Set
, созданным Collections.unmodifiableSet
, является то, что ImmutableSet
является типом. Вы можете пройти один вокруг и оставить в ясности, что набор является неизменным, используя ImmutableSet
, а не Set
во всем коде. С Collections.unmodifiableSet
возвращаемый тип - это просто Set
... поэтому он очищает только то, что множество немодифицируется в том месте, где оно создано, если вы не добавите Javadoc всюду, где вы проходите, что Set
говорит: "этот набор не поддается изменению".
Ответ 3
Кевин Бурриллион (ведущий разработчик Guava) сравнивает неизменяемые/немодифицируемые коллекции в эту презентацию. В то время как презентация - два года, и она фокусируется на "Коллекциях Google" (которая теперь является подразделением Guava), это очень интересная презентация. API, возможно, изменился здесь и там (API Google Collections API был в бета-версии в то время), но концепции Google Collections/Guava по-прежнему актуальны.
Вы также можете быть заинтересованы в этом другом вопросе SO (в чем разница между google ImmutableList и Collections.unmodifiableList()).
Ответ 4
Разница между двумя, не указанными в других ответах, заключается в том, что ImmutableSet
не позволяет значения null
, как описано в Javadoc
Высокопроизводительный неизменяемый набор с надежным, заданным пользователем порядком итерации. Не разрешает нулевые элементы.
(Такое же ограничение применяется к значениям во всех неизменяемых коллекциях Guava.)
Например:
ImmutableSet.of(null);
ImmutableSet.builder().add("Hi").add(null); // Fails in the Builder.
ImmutableSet.copyOf(Arrays.asList("Hi", null));
Все они не работают во время выполнения. Напротив:
Collections.unmodifiableSet(new HashSet<>(Arrays.asList("Hi", null)));
Это нормально.