이펙티브 자바를 보다 보면, 표준 예외를 사용하라는 item이 있습니다. 여기에 언급되는 exception들을 보면 Collections에서도 자주 보이는 예외가 몇 개 있는데요. 이번 시간에는 이 중에 UnsupportedOperationException에 대해서 보도록 하겠습니다.

 


 저번에 예를 들었던 것 중에, CopiesList를 들고 오겠습니다. 이것은 AbstractList를 상속받는다고 되어 있어요.

 

 명세를 보면, immutable list를 리턴한다고 되어 있어요. 저번에 본 바로는 CopiesList가 Collection 내부에 private 클래스로 되어 있었어요. 그리고, 계속 읽어보면, n copies of the specified Object라고 되어 있는데요. 특수 오브젝트의 n개의 복사 배열 정도라고 생각하면 편해요.

 

 즉, 특수 오브젝트와, 그것이 몇 개 있는지에 대한 정보는 초기화가 되고 나서 변하면 안 되는 것이므로, 생성자에서 초기화를 해 주게끔 하였을 겁니다. 보통 이 경우, final과 같이 써먹게 됩니다.

 

 이렇게요. 중요한 것은 원소 갯수 n과 대상인 element는 final로 선언했다는 점입니다. 이러면 초기화가 되고 element가 가리키는 대상하고, n은 변하지 않습니다.

 

 생성자에서 이 일을 수행했다면, 그 이후에 객체의 상태는 바뀌지 않습니다. frozen이 되었다고 합니다.

 


 List는 add와 remove가 존재합니다. 각각 원소를 추가하고 제거를 합니다. CopiesList도 List를 상속한 것입니다. 

 

 그러니, remove와 add 같은 것은 어딘가에서 상속을 받거나, 혹은 override를 할 겁니다.

 

 

 그런데, 아무리 찾아봐도, add나 remove는 볼 수 없습니다. CopiesList 안에는 없다는 이야기입니다. 그러면 어디서 들고 올까요?

 

 

 예제를 하나 작성해 보겠습니다. 3이라는 Integer 객체가 60개 있는 CopiesList를 생성하고, add 메서드를 호출해 보겠습니다.

 

 그러면 예외가 발생했음을 알 수 있어요. 어떤 것인가요? 이 글에서 설명할 UnsupportedOperationException입니다. 연산이 지원되지 않는데 하려고 시도할 때 던지게 됩니다. 이는 당연한 것인데요. Integer 객체 3이 60개 복사된 List가 중요합니다. 중간에 상태가 바뀌었다고 해 봅시다. 예를 들어, 3이 하나 더 추가가 되었다고 하면 어떨까요? n이 60에서 61이 됩니다.

 

 그러면 객체 3이 60개 복사된 List의 상태가 위와 같이 변하게 됩니다. 아니면 복사할 대상이 4로 바뀌었다. 그러면 어떤가요?

 

 

 Integer 객체 3이 60개 복사된 List의 상태가 이렇게 바뀌는 것입니다. 말이 안 되네요. 변경을 지원하면 안 됩니다. 따라서, write 연산에 UnsupportedOperationException을 띄우게 됩니다. 한 마디로 허용되지 않는 연산인 셈입니다. 실제로 trace를 따라가 보겠습니다.

 

 

 먼저, 107번째 줄의 메소드가 호출이 됩니다. 이것은 108번째 줄에서 int와 Element를 받는 또 다른 add를 호출하게 됩니다. 

 

 예외를 날립니다. 그런데, 왜 이렇게 처리를 했을까요? AbstractList class를 보면 꽤 긴 주석이 클래스 선언부 위에 있는데요. 이 긴 주석 중에서, variable한 List라면 add와 remove 같은 것을 override 하라는 문구 또한 있음을 알 수 있습니다. 이를 통해 추측할 수 있는 점은, 크기가 변하는 ArrayList나 LinkedList도 있지만, 그렇지 않아서 add나 remove 연산을 지원하지 말아야 하는 List도 있다는 점입니다.

 

 이것 때문에, AbstractList의 remove나 add에서 지원되지 않는 연산 예외를 떨구게 된 것입니다. 그러한 연산을 지원되게 하기 하려면, override를 하게끔 한 셈입니다.