1. 용어 정리
- List<E>와 같은 형식은 제네릭 클래스와 인터페이스로서 제네릭 자료형이라고 한다.
- 제네릭 자료형은 raw Type인 무인자 자료형을 같는다. List<E>의 raw type은 List이다.
- raw type을 통해 사용하면 추후에 element를 사용할 시 캐스팅을 잘 해주어야 한다. 그렇기에 형 안정성 확보를 위해 컬렉션에 담길 객체의 자료형이 무엇인지 알려준다.
2. raw type vs generic type
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | // 문제 1 (캐스팅 오류) List a = new ArrayList(); a.add(generic); for (Iterator i = a.iterator(); i.hasNext();) { (Dv) i.next(); // 잘못된 캐스팅으로 ClassCastException 발생 } // 형 안정성 확보를 위해 raw type이 아닌 제네릭 자료형을 사용한다. // 제네릭 자료형을 사용할 시 캐스팅도 필요없다. List<Generic> a = new ArrayList<>(); // 문제 2 ( unsafeAdd ) // raw type을 사용할 경우에 list에 데이터가 서로 다른 자료 불변형 형태가 나타날 수 있다. public static void main (String args[]) { List<String> a = new ArrayList<>(); a.add("babo"); setData(a, 12); } public static void setData(List list, int data) { list.add(data); } | cs |
위의 예를 보면 알지만 무인자 자료형을 사용할 시
잘못된 객체를 집어넣어야 하거나 캐스팅 실수등이 있을 수 있기에 제네릭 자료형을 꼭 사용하는 것이 좋다.
그렇다면 왜 위험한 무인자 자료형 (raw type)을 자바는 아직도 지원을 하는가?
그 이유는 예전에 만들어진 코드들이 무인자 자료형으로 만들어져서 이를 위한 호환성 때문이다.
그래서 만약 꼭 무인자 자료형이 쓰고 싶다거나
컴파일러에게 어떠한 자료형도 들어갈 수 있다고 알려주기 위해서는 다음과 같이 Object를 Generic Type으로 지정해 주어야 한다.
1 2 3 | List<Object> = new ArrayList<>(); public void setData(List<Object> list); | cs |
3. raw type vs wild card
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | // raw type public static void printSet(Set<?> s) { s.add(10);//this line is illegal for (Object o : s) { System.out.println(o); } } // wildcard public static void printSet(Set s) { s.add("2"); for (Object o : s) { System.out.println(o); } } | cs |
무인자 자료형을 사용할 경우
넘어오는 Set의 타입이 어떤 것인지 상관업이 어떤 형태의 데이터를 집어 넣을 수 있다.
이점 때문에 오류가 발생한다.
예를 들어 Set의 타입이 integer인 경우에 위의 코드에서는 String 객체를 집어넣으려고 하기 때문에 오류가 발생할 수 있다.
하지만 와일드 카드의 경우에는 null이외의 어떠한 값도 넣을 수 없기 때문에 무분별한 데이터 조작으로 인해 오류가 발생하는 것을 막을 수 있다.
또한
무인자 자료형은 아무런 객체나 넣을 수 있어서,
맨위의 예로 들었던 자료형 불변식이 쉽게 깨질 수 있다.
그렇기 때문에 와일드 카드는 안전하지만 무인자 자료형(raw type)은 안전하지 않다.
4. 무인자 자료형을 꼭 사용해야 하는 경우
1) 클래스 리터럴에는 반드시 무인자 자료형을 사용해야 한다.
=> 자바 표준에 따르면, 클래스 리터럴에는 형인자 자료형을 쓸 수 없다.
1 2 3 | List.class, String[].class. int.class는 가능 List<?>.class, List<String>.class는 불가능 | cs |
2) instanceof는 와일드카드 방식과 무인자 자료형이 동일하므로 코드가 지저분해 보이지 않도록 무인자 자료형을 쓰도록 하자.
1 2 3 4 | if ( data instanceof Set) { // 하지만 주의 할 것은 set이 맞을 경우에는 다시 와일드카드로 캐스팅 해주어야 한다. Set<?> m = (Set<?>) data; } | cs |
결론.
안전하게 사용하기 위해서는 예외사항을 제외하고는 무인자 자료형을 사용하지말자.
'JAVA > Effective Java' 카테고리의 다른 글
제네릭 - 규칙 25 배열 대신 리스트를 써라 (0) | 2018.05.29 |
---|---|
제네릭 - 규칙 24 무점검 경고를 제거하라 (0) | 2018.05.29 |
클래스와 인터페이스 - 규칙22 멤버 클래스는 가능하면 static으로 선언하라. (0) | 2018.05.29 |
클래스와 인터페이스 - 규칙 21 전략을 표현하고 싶을 때는 함수 객체를 사용하라. (0) | 2018.05.29 |
클래스와 인터페이스 - 규칙 20 태그 달린 클래스 대신 클래스 계층을 사용하라. (0) | 2018.05.29 |