알고리즘 문제를 풀던 도중 UnsupportedOperationException 에러가 발생했다.
처음보는 예외기도 하고 어떤 경우에 발생하는지 정리해놓기 위해 작성한다.
우선 Oracle Java Reference 에서 찾아보기로 했다.
프로그래머스 Java 컴파일 옵션에 맞게 14 버전을 찾아보았고 설명은 위와 같다.
요청된 작업이 지원되지 않는다는 것을 나타내기 위해 throw 된다는 것과 Collection 프레임워크에 대한 예외임을 알 수 있다.
다른 사례들을 검색해본 결과 수정할 수 없는 ArrayList 자료형에 대해 작업을 수행하려다 이 예외가 발생하는 경우가 많았다.
내 경우는 다음과 같다.
List<Character> copied = List.copyOf(charList);
for(Character c : copied){
int index = copied.indexOf(c);
List<Character> currentNum = new ArrayList<>();
makeExistedNums(copied, index, currentNum);
}
위 코드에서 copied 라는 charList 의 복사본을 만들었고 makeExistedNums 라는 메서드에서 copied 리스트의 원소를 remove 한다.
이 때 UnsupportedOperationException 이 발생하는 것이다.
원인을 찾아본 결과는 다음과 같다.
ArrayList 의 상위 인터페이스인 List 의 copyOf 설명이다. 수정 불가능한 List 를 반환한다.
내 경우 makeExistedNums 에서 깊은 복사된 리스트가 필요했기에 단순 대입이 아닌 자바 지원 메서드를 사용한 것이었는데 수정 불가능한 자료형을 반환한다는 것을 숙지하지 못했다.
"unmodifiable List" 에 대한 설명을 더 찾아보자면 ...
[간단 요약 번역]
List.of 와 List.copyOf 정적 팩토리 메서드는 수정 불가능한 리스트를 생성하기 위한 편리한 방법을 제공한다. 여기서 생성된 리스트들은 다음 특징을 가진다.
1. 수정 불가능함. 원소가 추가, 삭제, 대체 될 수 없다. 정해진 것 외의 메서드를 호출하면 "UnsupportedOperationException" 을 throw 한다.
2. null 원소를 허용하지 않는다. null 원소 생성을 시도하면 NullPointerException 을 throw 한다.
3. 모든 원소가 직렬화가 가능하다면 List 도 직렬화가 가능하다.
4. 리스트 원소의 순서는 제공된 인자 혹은 원소의 순서와 같다.
5. value based (값 기반) 클래스다. 여기에 사용된 팩토리 메서드는 새로운 인스턴스를 만들거나 이미 존재하는 인스턴스를 재사용할 수 있다. 그러므로 참조 비교(==), hash code, synchronization 과 같은 작업을 피해야한다.
(변수의 참조를 비교하거나 하지않고, collection 에 포함되어있는 각 값을 비교하는 것으로 이해)
6. 이들은 Serialized Form 페이지에 맞춰 직렬화된다.
위 설명에 따르면 수정 불가능한 리스트에 대해 remove 를 시도한 것도 잘못되었지만,
깊은 복사를 위해 List.copyOf 메서드를 사용한 의도 자체도 잘못되었다는 것을 알 수 있다.
[해결법]
List 자료형의 깊은 복사를 위해서는 "new 연산자" 를 사용해야한다.
List<Character> copied = new ArrayList<>(charList);
잘못된 코드를 고치면 위와 같다.
'학습 기록 > 자바' 카테고리의 다른 글
Java 람다, 함수형 인터페이스, 동작 파라미터화 (1) | 2025.03.12 |
---|---|
Enum 비교는 '==' 을 사용하자 (0) | 2024.02.22 |
자바는 call by value 만 존재한다 (0) | 2023.07.02 |