From 799220f1bee501f32b49291a816e4257a1dc5609 Mon Sep 17 00:00:00 2001 From: 2heunxun Date: Wed, 6 Aug 2025 22:21:52 +0900 Subject: [PATCH 1/4] =?UTF-8?q?docs:=20item26=20=EB=82=B4=EC=9A=A9?= =?UTF-8?q?=EC=A0=95=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...1\353\235\274_\354\212\271\355\227\214.md" | 170 ++++++++++++++++++ 1 file changed, 170 insertions(+) create mode 100644 "item26/item26 _ \341\204\205\341\205\251 \341\204\220\341\205\241\341\204\213\341\205\265\341\206\270\341\204\213\341\205\263\341\206\257 \341\204\211\341\205\241\341\204\213\341\205\255\341\206\274\341\204\222\341\205\241\341\204\214\341\205\265 \341\204\206\341\205\241\353\235\274_\354\212\271\355\227\214.md" diff --git "a/item26/item26 _ \341\204\205\341\205\251 \341\204\220\341\205\241\341\204\213\341\205\265\341\206\270\341\204\213\341\205\263\341\206\257 \341\204\211\341\205\241\341\204\213\341\205\255\341\206\274\341\204\222\341\205\241\341\204\214\341\205\265 \341\204\206\341\205\241\353\235\274_\354\212\271\355\227\214.md" "b/item26/item26 _ \341\204\205\341\205\251 \341\204\220\341\205\241\341\204\213\341\205\265\341\206\270\341\204\213\341\205\263\341\206\257 \341\204\211\341\205\241\341\204\213\341\205\255\341\206\274\341\204\222\341\205\241\341\204\214\341\205\265 \341\204\206\341\205\241\353\235\274_\354\212\271\355\227\214.md" new file mode 100644 index 0000000..3d77d83 --- /dev/null +++ "b/item26/item26 _ \341\204\205\341\205\251 \341\204\220\341\205\241\341\204\213\341\205\265\341\206\270\341\204\213\341\205\263\341\206\257 \341\204\211\341\205\241\341\204\213\341\205\255\341\206\274\341\204\222\341\205\241\341\204\214\341\205\265 \341\204\206\341\205\241\353\235\274_\354\212\271\355\227\214.md" @@ -0,0 +1,170 @@ +# 아이템 26 - 로 타입을 사용하지 마세요 + +## 선요약 + +- **로 타입을 사용하면 런타임에 예외**가 일어날 수 있으므로 사용하면 안 된다 +- 로 타입은 제네릭이 도입되기 **이전 코드와의 호환성을 위해 제공**될 뿐이다 + +## 제네릭을 사용하는 이유 + +- 컴파일 시점에서 타입을 체크함으로써 **타입 안정성**을 제공함 +- **타입체크와 형변환을 생략**함으로써 코드가 간결해짐 + +--- + +# 로 타입이란 ? + +- 제네릭 타입에서 타입 매개변수를 전혀 사용하지 않는 경우를 의미함 +- List의 로 타입은 List다 + +```java + // 제네릭을 지정하지 않은 로 타입 + List rawList = new ArrayList(); // Raw Type + + // 다양한 타입을 섞어서 넣을 수 있음 (타입 안정성 없음) + rawList.add("Hello"); + rawList.add(123); + rawList.add(true); + + // 꺼낼 때는 Object로 반환 → 형변환 필요 + String s = (String) rawList.get(0); // OK + Integer i = (Integer) rawList.get(1); // OK + // Integer num = (Integer) rawList.get(0); // 런타임 ClassCastException + + System.out.println(rawList); +``` + +### 로 타입을 사용하면 안 되는 이유 + +- 로 타입은 타입 선언에서 제네릭 타입 정보가 전부 지워진 것 처럼 작동한다. +- 즉, 컴파일 시점에서 타입을 체크하지 않고 런타임 시점에서 타입을 체크한다. + +```java +// Stamp 인스턴스만 취급할 거다. +private final Collection stamps = ...; + +// 실수로 동전 넣는다. +stamps.add(new Coin(...)); // 'unchecked call' 경고를 뱉지만 실행이 된다. +``` + +제네릭을 활용하면 타입 선언 자체에서 알 수 있다. + +```java +private final Collection stamps = ... ; +``` + +타입 안전성이 확보되어서 컴파일 시에 다른 클래스를 넣으려하면 오류가 발생한다. + +**로 타입을 쓰면 제네릭이 주는 안전성과 표현력을 잃는다.** + +## 쓰지말자. + +그럼 왜 만들어 놨을까? 호환성 때문이다. 제네릭이 자바 1.5에 나오면서 이전 코드와 호환을 해야하기 때문이다. 그래서 로 타입을 지원하고 제네릭 구현에는 소거 사용하기로 했다. + +### 에러는 가능한 한 발생 즉시 우리 개발 환경에 보이는 것이 좋다 즉 + +→ 이상적으로는 컴파일 할 때 발견하는 것이 좋다… → 공감. + +만약 로타입을 쓴다고 가정해보자 + +```jsx +public class Item26 { + + public static void main(String[] args) { + List list = new ArrayList(); + list.add(10); + list.add(20); + list.add("30"); + + Integer i = (Integer)list.get(2); //런타임 에러 발생 + + System.out.println(list); + } +} +``` + +이러면 + +즉 → 문제를 겪는 코드와 원인을 제공하는 코드가 물리적으로 상당히 떨어져 있다. + +## 로 타입의 대안 + +1. 임의 객체를 허용한다. + +```java +public class Item26 { + + public static void main(String[] args) { + List strings = new ArrayList<>(); + unsafeAdd(strings, Integer.valueOf(42)); // 컴파일 에러 발생 + String s = strings.get(0); // 컴파일러가 자동으로 형변환 코드를 넣어준다 + } + + private static void unsafeAdd(List list, Object o) { + list.add(o); + } +} +``` + +컴파일 구역에서 자체 차단을 시켜버림 + +1. 비한정적인 와일드카드 타입 + +```java +public int numElementsInCommon(Set s1, Set s2) { + int result = 0; + for (Object o1 : s1) + if (s2.contains(o1)) + result++; + return result; +} +``` + +비 한정적인 와일드 카드 타입을 사용해 더욱 안전하게 코드를 작성할 수 있다. + +## 로타입은 언제쓸까 ? + +## 1. Class 리터럴에서의 로타입 사용 예외 + +- **Java 명세 제약** + + 제네릭 파라미터를 붙인 타입은 .class에 사용할 수 없음 + + - 허용: + - List.class + - String[].class + - int.class + - 금지: + - List.class + - List.class + +```java + +Class c1 = List.class; +Class c2 = String[].class; +Class c3 = int.class; + +// 컴파일 에러 +Class> c4 = List.class; +Class> c5 = List.class; +``` + +## 2. instanceof 연산자와 로타입 vs 와일드카드 + +- **런타임 동작** + + 제네릭은 타입 소거(type erasure) 되어, raw 타입이나 모두 같은 클래스 판별 + +- **문법 차이** + - 허용: + + ```java + if (obj instanceof List) { /* OK */ } + if (obj instanceof List) { /* OK */ } + ``` + + - 금지: + + ```java + if (obj instanceof List) { /* 컴파일 에러 */ } + ``` \ No newline at end of file From 99e402d5bcfb6e126d2c3409feefc3a9e83edf3a Mon Sep 17 00:00:00 2001 From: 2heunxun Date: Wed, 13 Aug 2025 21:26:45 +0900 Subject: [PATCH 2/4] =?UTF-8?q?docs:=20item35=20=EB=82=B4=EC=9A=A9?= =?UTF-8?q?=EC=A0=95=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...\353\235\274_ \354\212\271\355\227\214.md" | 51 +++++++++++++++++++ 1 file changed, 51 insertions(+) create mode 100644 "item35/item36_ordinal \353\251\224\354\204\234\353\223\234 \353\214\200\354\213\240 \354\235\270\354\212\244\355\204\264\354\212\244 \355\225\204\353\223\234\353\245\274 \354\202\254\354\232\251\355\225\230\353\235\274_ \354\212\271\355\227\214.md" diff --git "a/item35/item36_ordinal \353\251\224\354\204\234\353\223\234 \353\214\200\354\213\240 \354\235\270\354\212\244\355\204\264\354\212\244 \355\225\204\353\223\234\353\245\274 \354\202\254\354\232\251\355\225\230\353\235\274_ \354\212\271\355\227\214.md" "b/item35/item36_ordinal \353\251\224\354\204\234\353\223\234 \353\214\200\354\213\240 \354\235\270\354\212\244\355\204\264\354\212\244 \355\225\204\353\223\234\353\245\274 \354\202\254\354\232\251\355\225\230\353\235\274_ \354\212\271\355\227\214.md" new file mode 100644 index 0000000..9e8d8ad --- /dev/null +++ "b/item35/item36_ordinal \353\251\224\354\204\234\353\223\234 \353\214\200\354\213\240 \354\235\270\354\212\244\355\204\264\354\212\244 \355\225\204\353\223\234\353\245\274 \354\202\254\354\232\251\355\225\230\353\235\274_ \354\212\271\355\227\214.md" @@ -0,0 +1,51 @@ +# ordinal 메서드 대신 인스턴스 필드를 +사용하라 + +```java +public enum Ensemble { +SOLO, DUET, TRIO, QUARTET, QUINTET, +SEXTET, SEPTET, OCTET, NONET, DECTET; +public int numberOfMusicians() { return ordinal() + 1; } +} +``` + +먼저 코드를 보면 Enum형식의 solo, duet, trio, quartet 등등 이 적혀있고 0부터 시작이므로 numberOfMusicians에 의해 1씩 더해줘 각각의 숫자가 의마하는 바를 갖추고 있습니다. + +## 여기서 문제점 ! + +현재는 10까지 밖에 선언이 안되어있지만 83이 필요하다. +그러면 numberOfMusicians를 활용해 값을 매기는 거기 때문에 11번째에 83을 의미하는 것을 끼워 넣으면 + +83이 아닌 12를 의미하게 된다! + +Double_Trio를 넣고싶은데… + +Double_Trio = 3 x 2 = 6을 의미하지만 sextet이 살아있고 그걸 한칸씩 밀게되면 뒤에는 모두 의미하는 바와 다른 값들이 들어가게 된다. + +--- + +```java +public enum Ensemble { +SOLO(1), DUET(2), TRI0(3), QUARTET(4), QUINTET(5), +SEXTET(6), SEPTET(7), 0CTET(8), D0UBLE_QUARTET(8), +N0NET(9), DECTET(10)r TRIPLE_QUARTET(12); +private final int numberOfMusicians; +Ensemble(int size) { this.numberOfMusicians = size; } +public int numberOfMusicians() { return numberOfMusicians; } +} +``` + +위에 코드처럼 인스턴스 필드로 값을 저장하면 + +즉 ordinal 대신, 생성자 매개변수로 직접 값을 저장한다. + +Ensemble(int size) + +너가 선언할 용어(실제 값) 이 되는거다. + +그러면 순서에 상관을 쓰지 않아도 되고, 멀리 있는 값을 따와도 문제 없고, 또한 중복인 값이 들어가도 끄떡없다. + +결론 + +## "순서에 의존하지 말고, 필요한 값을 직접 필드로 들고 있어라." +### 그래야 enum 수정, 확장해도 안전하고 유지보수가 쉬움. \ No newline at end of file From 5a33f2b68ef7d8790f5742bd8cd5a045ec55cda2 Mon Sep 17 00:00:00 2001 From: Seunghun Yu <168928296+2heunxun@users.noreply.github.com> Date: Wed, 13 Aug 2025 21:27:42 +0900 Subject: [PATCH 3/4] =?UTF-8?q?Update=20item36=5Fordinal=20=EB=A9=94?= =?UTF-8?q?=EC=84=9C=EB=93=9C=20=EB=8C=80=EC=8B=A0=20=EC=9D=B8=EC=8A=A4?= =?UTF-8?q?=ED=84=B4=EC=8A=A4=20=ED=95=84=EB=93=9C=EB=A5=BC=20=EC=82=AC?= =?UTF-8?q?=EC=9A=A9=ED=95=98=EB=9D=BC=5F=20=EC=8A=B9=ED=97=8C.md?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...251\355\225\230\353\235\274_ \354\212\271\355\227\214.md" | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git "a/item35/item36_ordinal \353\251\224\354\204\234\353\223\234 \353\214\200\354\213\240 \354\235\270\354\212\244\355\204\264\354\212\244 \355\225\204\353\223\234\353\245\274 \354\202\254\354\232\251\355\225\230\353\235\274_ \354\212\271\355\227\214.md" "b/item35/item36_ordinal \353\251\224\354\204\234\353\223\234 \353\214\200\354\213\240 \354\235\270\354\212\244\355\204\264\354\212\244 \355\225\204\353\223\234\353\245\274 \354\202\254\354\232\251\355\225\230\353\235\274_ \354\212\271\355\227\214.md" index 9e8d8ad..ca4dbf4 100644 --- "a/item35/item36_ordinal \353\251\224\354\204\234\353\223\234 \353\214\200\354\213\240 \354\235\270\354\212\244\355\204\264\354\212\244 \355\225\204\353\223\234\353\245\274 \354\202\254\354\232\251\355\225\230\353\235\274_ \354\212\271\355\227\214.md" +++ "b/item35/item36_ordinal \353\251\224\354\204\234\353\223\234 \353\214\200\354\213\240 \354\235\270\354\212\244\355\204\264\354\212\244 \355\225\204\353\223\234\353\245\274 \354\202\254\354\232\251\355\225\230\353\235\274_ \354\212\271\355\227\214.md" @@ -1,5 +1,4 @@ -# ordinal 메서드 대신 인스턴스 필드를 -사용하라 +# ordinal 메서드 대신 인스턴스 필드를 사용하라 ```java public enum Ensemble { @@ -48,4 +47,4 @@ Ensemble(int size) 결론 ## "순서에 의존하지 말고, 필요한 값을 직접 필드로 들고 있어라." -### 그래야 enum 수정, 확장해도 안전하고 유지보수가 쉬움. \ No newline at end of file +### 그래야 enum 수정, 확장해도 안전하고 유지보수가 쉬움. From 1c66833d5ff4248e02617be6b1841ac38acf418c Mon Sep 17 00:00:00 2001 From: Seunghun Yu <168928296+2heunxun@users.noreply.github.com> Date: Wed, 13 Aug 2025 23:01:13 +0900 Subject: [PATCH 4/4] =?UTF-8?q?Update=20item36=5Fordinal=20=EB=A9=94?= =?UTF-8?q?=EC=84=9C=EB=93=9C=20=EB=8C=80=EC=8B=A0=20=EC=9D=B8=EC=8A=A4?= =?UTF-8?q?=ED=84=B4=EC=8A=A4=20=ED=95=84=EB=93=9C=EB=A5=BC=20=EC=82=AC?= =?UTF-8?q?=EC=9A=A9=ED=95=98=EB=9D=BC=5F=20=EC=8A=B9=ED=97=8C.md?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...32\251\355\225\230\353\235\274_ \354\212\271\355\227\214.md" | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git "a/item35/item36_ordinal \353\251\224\354\204\234\353\223\234 \353\214\200\354\213\240 \354\235\270\354\212\244\355\204\264\354\212\244 \355\225\204\353\223\234\353\245\274 \354\202\254\354\232\251\355\225\230\353\235\274_ \354\212\271\355\227\214.md" "b/item35/item36_ordinal \353\251\224\354\204\234\353\223\234 \353\214\200\354\213\240 \354\235\270\354\212\244\355\204\264\354\212\244 \355\225\204\353\223\234\353\245\274 \354\202\254\354\232\251\355\225\230\353\235\274_ \354\212\271\355\227\214.md" index ca4dbf4..ec077fa 100644 --- "a/item35/item36_ordinal \353\251\224\354\204\234\353\223\234 \353\214\200\354\213\240 \354\235\270\354\212\244\355\204\264\354\212\244 \355\225\204\353\223\234\353\245\274 \354\202\254\354\232\251\355\225\230\353\235\274_ \354\212\271\355\227\214.md" +++ "b/item35/item36_ordinal \353\251\224\354\204\234\353\223\234 \353\214\200\354\213\240 \354\235\270\354\212\244\355\204\264\354\212\244 \355\225\204\353\223\234\353\245\274 \354\202\254\354\232\251\355\225\230\353\235\274_ \354\212\271\355\227\214.md" @@ -27,7 +27,7 @@ Double_Trio = 3 x 2 = 6을 의미하지만 sextet이 살아있고 그걸 한칸 public enum Ensemble { SOLO(1), DUET(2), TRI0(3), QUARTET(4), QUINTET(5), SEXTET(6), SEPTET(7), 0CTET(8), D0UBLE_QUARTET(8), -N0NET(9), DECTET(10)r TRIPLE_QUARTET(12); +N0NET(9), DECTET(10), TRIPLE_QUARTET(12); private final int numberOfMusicians; Ensemble(int size) { this.numberOfMusicians = size; } public int numberOfMusicians() { return numberOfMusicians; }