Как сделать Collection или Map неизменяемой
Часто необходимо создавать версию только для чтения Collection или Map. Класс Collections позволяет вам сделать это, передав оригинальный контейнер в метод, который вернет версию только для чтения. Есть четыре варианта этого метода, каждый них для Collection (если вы не хотите трактовать Collection, как более специфический тип), List, Set и Map. Этот пример показывает правильный способ построения версии только для чтения для каждого класса:
//: c09:ReadOnly.java
// Использование методов Collections.unmodifiable.
import java.util.*; import com.bruceeckel.util.*;
public class ReadOnly { static Collections2.StringGenerator gen = Collections2.countries; public static void main(String[] args) { Collection c = new ArrayList(); Collections2.fill(c, gen, 25); // Вставление данных
c = Collections.unmodifiableCollection(c); System.out.println(c); // Чтение закончилось удачно
c.add("one"); // Не могу изменить это
List a = new ArrayList(); Collections2.fill(a, gen.reset(), 25); a = Collections.unmodifiableList(a); ListIterator lit = a.listIterator(); System.out.println(lit.next()); // Чтение закончилось удачно
lit.add("one"); // Не могу изменить это
Set s = new HashSet(); Collections2.fill(s, gen.reset(), 25); s = Collections.unmodifiableSet(s); System.out.println(s); // Чтение закончилось удачно
//! s.add("one"); // Не могу изменить это
Map m = new HashMap(); Collections2.fill(m, Collections2.geography, 25); m = Collections.unmodifiableMap(m); System.out.println(m); // Чтение закончилось удачно
//! m.put("Ralph", "Howdy!");
} } ///:~
В каждом случае вы должны заполнить контейнер значимыми данными прежде, чем будете делать его только для чтения. Как только он будет загружен, лучший подход состоит в замене существующей ссылки на ссылку, произведенную вызовом метода, запрещающим изменения. Это способ позволяет вам избежать риска случайного изменения, так как вы делаете контейнер не изменяемым. С другой стороны, этот инструмент также позволяет вам сделать ваш неизменяемый контейнер, как private внутри класса и возвращать ссылку только для чтения на этот контейнер из вызова метода. Так что вы можете менять его внутри класса, но все остальные смогут только читать его.
Вызов “неизменяемого” метода для определенного типа не является причиной проверки во время компиляции, но как только будет вызвана трансформация, то любой вызов метода, изменяющегося содержимое определенного контейнера, станет причиной возникновения UnsupportedOperationException.