-
[Java] UnsupportedOperationException - 배열 asList 관련 에러우아한 테크코스/테크코스 2020. 2. 17. 21:22반응형
asList한 Arrays에 add를 하면 해당 에러 발생
UnsupportedOperationException, add를 하고 싶다면 addAll() 또는 생성자를 통해 하도록(아래 코드 참고)
깊은 복사와 얕은 복사깊은 복사 : deep copy : call by value
복사한 원본 또는 복사본 모두 수정이 서로에게 영향을 미치지 않음 - 값을 복사하기 때문
Cloneable을 상속받은 객체를 clone() 메서드로 복사함
얕은 복사 : shallow copy : call by reference
복사한 원본 또는 복사본 모두 수정이 서로에게 영향을 미침 - 주소를 복사하여 서로 참조하기 때문
= 기호로 복사함
List의 덜 깊은 복사?(공식 용어 아님)
List를 대체할 때는 (set API이용) 대체를 해주는데(바꾸는 값)
List를 대체하지 않을 때는(직접 수정, 메서드 등을 통해) 대체가 되지 않고 기존의 주소에서 해당 주소를 참조하는 듯(?)
즉, clone을 해야 완전한 복사인 듯 함!
(나중에 clone 하고 코드 추가해두기)
테스트 코드(학습 테스트)
import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatThrownBy; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; public class TestException { @DisplayName("Arrays.asList의 경우, add시 UnsupportedOperationException 발생, 얕은 복사") @Test void unsupportedOperationException() { String string = "가,나,다"; List<String> stringList = Arrays.asList(string.split(",")); assertThatThrownBy(() -> stringList.add("라")) .isInstanceOf(UnsupportedOperationException.class); } @DisplayName("addAll(Arrays.asList())의 경우, (덜) 깊은 복사") @Test void success() { String string = "가,나,다"; List<String> stringList = new ArrayList<>(); stringList.addAll(Arrays.asList(string.split(","))); stringList.add("라"); assertThat(stringList.get(3)).isEqualTo("라"); } @DisplayName("new ArrayList<String>(Arrays.asList())의 경우도 (덜) 깊은 복사") @Test void successCopy() { String string = "가,나,다"; List<String> stringList = new ArrayList<>(Arrays.asList(string.split(","))); stringList.add("라"); assertThat(stringList.get(3)).isEqualTo("라"); } @DisplayName("얕은/깊은 복사 테스트") @Test void copy() { List<String> stringListBefore = new ArrayList<>(); stringListBefore.add(new String("가")); stringListBefore.add(new String("나")); stringListBefore.add(new String("다")); List<String> stringDeeps1 = new ArrayList<>(); List<String> stringDeeps2 = new ArrayList<>(stringListBefore); List<String> stringShallow = stringListBefore; stringDeeps1.addAll(stringListBefore); stringListBefore.add("라"); // 변경 전 - Reference copy이기 때문에 true assertThat(stringDeeps1.get(0) == stringListBefore.get(0)).isTrue(); assertThat(stringDeeps2.get(0) == stringListBefore.get(0)).isTrue(); assertThat(stringShallow.get(0) == stringListBefore.get(0)).isTrue(); stringListBefore.set(0, new String("가")); // 변경 후 assertThat(stringDeeps1.get(0) == stringListBefore.get(0)).isFalse(); assertThat(stringDeeps2.get(0) == stringListBefore.get(0)).isFalse(); assertThat(stringShallow.get(0) == stringListBefore.get(0)).isTrue(); assertThatThrownBy(() -> stringDeeps1.get(3)) .isInstanceOf(IndexOutOfBoundsException.class); assertThatThrownBy(() -> stringDeeps2.get(3)) .isInstanceOf(IndexOutOfBoundsException.class); assertThat(stringShallow.get(3)).isEqualTo("라"); stringListBefore.set(0, new String("가나다")); assertThat(stringDeeps1.get(0)).isEqualTo("가"); assertThat(stringDeeps2.get(0)).isEqualTo("가"); assertThat(stringShallow.get(0)).isEqualTo("가나다"); } @DisplayName("얕은/깊은 복사 테스트 - 중요!") @Test void copy2() { List<int[]> integerBefore = new ArrayList<>(); integerBefore.add(new int[]{1}); integerBefore.add(new int[]{2}); integerBefore.add(new int[]{3}); List<int[]> integerDeeps1 = new ArrayList<>(); List<int[]> integerDeeps2 = new ArrayList<>(integerBefore); List<int[]> integerShallow = integerBefore; integerDeeps1.addAll(integerBefore); integerBefore.add(new int[]{4}); assertThat(integerDeeps1.get(0)[0] == integerBefore.get(0)[0]).isTrue(); assertThat(integerDeeps2.get(0)[0] == integerBefore.get(0)[0]).isTrue(); assertThat(integerShallow.get(0)[0] == integerBefore.get(0)[0]).isTrue(); // 덜 깊은 복사 ? ? ? ! 진짜 깊은 복사는 clone으로 구현해야! integerBefore.get(0)[0] = 2; assertThat(integerDeeps1.get(0)[0] == integerBefore.get(0)[0]).isTrue(); assertThat(integerDeeps2.get(0)[0] == integerBefore.get(0)[0]).isTrue(); assertThat(integerShallow.get(0)[0] == integerBefore.get(0)[0]).isTrue(); } }
반응형'우아한 테크코스 > 테크코스' 카테고리의 다른 글
자바 빈(Java Bean)이란? (0) 2020.02.18 d2 coding 글꼴 적용(맥 / 인텔리제이) (0) 2020.02.18 [Java] 예외일 경우, 반복하여 실행하기 (2) 2020.02.15 2주차 리뷰 (0) 2020.02.15 정규표현식(Regular expression) (0) 2020.02.08