Collections.unmodifiableMap 메소드를 이용한 read-only 객체 만들기
웹 애플리케이션 기동 시 properties에 있는 설정 정보들을 컬렉션 객체에 저장하고 이를 가져다가 쓰는 경우가 많은데 이 객체에 변경을 막는 제약 조건을 걸고 싶을 때가 있다.
즉, read-only 한 객체를 만들고 싶은 경우인데 이럴 때 다음의 메소드를 사용하면 좋을 것 같다.
Collections.unmodifiableMap
Collections.unmodifiableList
해당 메소드는 파라미터로 전달 받은 컬렉션 객체에 어떠한 변경이라도 발생하면 예외를 return한다.
테스트 코드는 다음과 같다.
package collection;
import static org.hamcrest.CoreMatchers.*;
import static org.junit.Assert.*;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import org.junit.Test;
public class CollectionsTest {
@Test
public void unmodifyMapTest() {
Map<Integer, String> testMap = new HashMap<Integer, String>();
testMap.put(1, "test1");
testMap.put(2, "test2");
Map<Integer, String> unmodifyTestMap = Collections.unmodifiableMap(testMap);
assertThat("test1", is(unmodifyTestMap.get(1)));
assertThat("test2", is(unmodifyTestMap.get(2)));
boolean exceptionThrown = false;
try {
unmodifyTestMap.put(3, "test3"); // unmodifyTestMap 객체 변경 시 예외
} catch (UnsupportedOperationException ex) {
ex.printStackTrace();
exceptionThrown = true;
}
assertTrue(exceptionThrown);
}
}
문득 어떻게 해서 객체의 변경을 감지한 후 예외를 던지는지 궁금해 졌다.
unmodifiableMap 메소드는 다음과 같은 구조를 가지고 있고, UnmodifiableMap 클래스의 타입을 return한다.
public static <K,V> Map<K,V> unmodifiableMap(Map<? extends K, ? extends V> m) {
return new UnmodifiableMap<K,V>(m);
}
자~ 그럼 UnmodifiableMap 클래스를 들여다 보자.
Map 인터페이스를 구현한 UnmodifiableMap 클래스에서 put, remove, putAll 호출 시 UnsupportedOperationException 예외를 return하도록 설계되어 있다. (생각보다 간단하게 구현되어 있음. 역시 Java API)
private static class UnmodifiableMap<K, V> implements Map<K, V>, Serializable {
// use serialVersionUID from JDK 1.2.2 for interoperability
private static final long serialVersionUID = -1034234728574286014L;
private final Map<? extends K, ? extends V> m;
UnmodifiableMap(Map<? extends K, ? extends V> m) {
if (m == null)
throw new NullPointerException();
this.m = m;
}
public int size() {
return m.size();
}
public boolean isEmpty() {
return m.isEmpty();
}
public boolean containsKey(Object key) {
return m.containsKey(key);
}
public boolean containsValue(Object val) {
return m.containsValue(val);
}
public V get(Object key) {
return m.get(key);
}
public V put(K key, V value) {
throw new UnsupportedOperationException();
}
public V remove(Object key) {
throw new UnsupportedOperationException();
}
public void putAll(Map<? extends K, ? extends V> m) {
throw new UnsupportedOperationException();
}
public void clear() {
throw new UnsupportedOperationException();
}
}
인터페이스를 이용한 느슨한 설계가 어떤 장점을 주는지 확인할 수 있는 좋은 예인 것 같다.
'프로그래밍' 카테고리의 다른 글
숫자섞기 알고리즘 (0) | 2013.10.17 |
---|---|
자바스크립트 inline? external? (0) | 2013.10.17 |
sitemesh 설정 (0) | 2013.09.02 |
struts2 Missing artifact com.sun:tools:jar:1.5.0 해결 방법 (0) | 2013.09.02 |
리눅스에서 java 컴파일 및 실행 하기 (4) | 2013.08.09 |
Mockito를 이용한 테스트 (0) | 2013.08.07 |
Serializable 객체직렬화 (1) | 2013.07.30 |
jquery를 이용한 jsonp 처리 방법 (0) | 2013.07.11 |