개발

[제네릭] 타입 안전 이종 컨테이너.. 이거 어디에 사용할까?

오렌지색 귤 2022. 2. 21. 01:40
반응형

궁금증

 

이펙티브 자바 "아이템 33 - 타입 안전 이종 컨테이너를 고려하라"를 읽으면서 든 궁금증이다.

 

그래... 다양한 타입을 하나의 컬렉션 등에 넣기 위해, 예를 들어 Map의 key에는 클래스 리터럴 값을 넣고 value에는 Object를 받는다고 치자.

 

저 map에서 put과 get을 할때 메서드를 직접 구현해서 type.cast() 등을 활용해서 타입 안전하게 여러 타입을 넣을 수 있게 되었다.

 

교재에서는 이러한 동적 형변환으로 런타임 타입 안전성을 확보하는 방식을 java.util.Collections에 있는 checkedSet, checkedList, checkedMap 같은 메서드를 만들 때 적용했다고 한다.

 

그래 알겠다.. 이 래퍼들은 제네릭과 로 타입을 섞어 사용하는 애플리케이션에서 클라이언트 코드가 컬렉션에 잘못된 타입의 원소를 넣지 못하게 추적하는 데 도움을 준다고 한다.

 

근데 진짜 쓰긴 쓸까? 하는 궁금증이 들었다.

 

사실 다양한 타입을 하나의 컬렉션 안에 넣을 일이 있을까?

 

차라리 필요한 타입에 대한 컬렉션을 각각 만들어주는게 더 낫지 않을까? 하는 생각이 들었다.

 

 


해결

 

Stackoverflow나 Collections api를 뜯어봤지만, 별로 알 수 있는 것은 없었다.

 

그러다 Oracle의 공식 문서에서 checkedCollection을 만든 이유에 대해서 알 수 있었다.

 

 

Collections (Java Platform SE 6)

Rotates the elements in the specified list by the specified distance. After calling this method, the element at index i will be the element previously at index (i - distance) mod list.size(), for all values of i between 0 and list.size()-1, inclusive. (Thi

docs.oracle.com

 

checkedCollection은 해당 컬렉션의 동적으로 타입 안전한 view를 반환할 때 사용된다

 

checkedCollection에 잘못된 타입의 원소를 삽입하려 시도하는 순간 ClassCastException을 던질 것이다.

 

checkedCollection은 이전에 이미 들어가있던 원소에 대해서는 type safe를 보장하지 못하지만, 이후에 들어오는 접근에 대해서는 type safe 함을 보장한다.

 

 

그래서... 어디에 쓰는데?

 

두가지 목적을 가지고 만들어졌다.

 

1. 타입 안전성을 위해서

 

컴파일 타임에 type checking을 하는 제네릭 메커니즘은 unchecked casts에 의해 속절없이 무너질 수 있다.

 

근데 사실 무너진다해도 컴파일러가 unchecked 경고를 발생하므로 정말 큰 문제라고는 할 수 없다. (이것만으로는 checkedCollection을 굳이 쓸 필요가 없다)

 

다만 문제는 static type checking만으로는 충분치 않을 때가 있다는 것이다.

 

예를 들어 컬렉션을 서드 파티 라이브러리로 전달하는 경우를 상상해보라.

 

라이브러리 코드가 컬렉션에 잘못된 타입의 원소를 삽입하는 것을 피할 수 없을 지도 모른다.

 

2. 디버깅을 위해서

 

프로그램이 ClassCastException을 던지면서 오류가 발생한 상황을 상상해보자.

 

오류 메세지에서는 단순히 "잘못된 타입을 가진 원소가 매개변수화 컬렉션에서 꺼낸 순간 있었다"라는 말만 되풀이 할 것이다.

 

실제로 예외를 발생시키는 원소가 삽입되는 곳을 알려주지는 않는다.

 

이 상황에서 임시로 dynamically typesafe view를 반환하는 컬렉션으로 감싼 뒤 프로그램을 실행해보자.

 

// 변경 이전의 코드
Collection<String> c = new HashSet<String>();

// 변경 이후의 코드
Collection<String> c = Collections.checkedCollection(
				new HashSet<String>(), String.class);

 

코드를 변경한 뒤 프로그램을 다시 실행하게 되면 잘못된 타입을 가진 원소가 삽입되는 지점에서 에러가 발생할 것이다.

 

깔끔하게 문제의 원인을 바로 알 수 있게 되는 것이다.

 

문제가 해결되면, 변경 이전으로 코드를 복구한다.

 


아이템 33의 내용은 정말 어려워서 5번 정도는 읽은 것 같다.

 

추후 복습할 겸 내용을 정리해서 포스팅 해야겠다.

반응형