본문 바로가기
728x90

공부/이펙티브자바33

[이펙티브자바]item 33.타입 안전 이종 컨테이너를 고려하라. 아이고 어렵네~ 타입 안전 이종 컨테이너: 한 타입의 객체만 담을 수 있는 컨테이너가 아니라, 여러 다른 타입을 담을 수 있는 타입 안전한 컨테이너. 구현방법: 컨테이너 대신 키를 매개변수화한 다음, 컨테이너에 값을 넣거나 뺄 때 매개변수화환 키를 함께 제공하면 된다. 2023. 2. 17.
[이펙티브자바]item 32.제네릭과 가변인수를 함께 쓸 때는 신중하라. varargs 매개변수에 제네릭이나 매개변수화 타입이 포함되면 알기 어려운 컴파일 경고가 발생한다. public class Dangerous { static void dangerous(List... stringLists) { List intList = List.of(42); Object[] objects = stringLists; objects[0] = intList; // 힙 오염 발생 String s = stringLists[0].get(0); // ClassCastException } public static void main(String[] args) { dangerous(List.of("There be dragons!")); } } 매개변수화 타입의 변수가 다른 객체를 참조하면 힙 오염이 발생한.. 2023. 2. 16.
[이펙티브자바]item 31.한정적 와일드카드를 사용해 API 유연성을 높이라. 우선 읽고 가자. 불변성(무공변성, invariant) 상속 관계에 상관없이 자신의 타입만 허용하는 것을 뜻한다. Kotlin 에서는 따로 지정해주지 않으면 기본적으로 모든 Generic Class 는 무공변이다. Java 에서의 와 같다. 공변성(covariant) 자기 자신과 자식 객체를 허용한다. Java 에서의 와 같다. Kotlin 에서는 out 키워드를 사용해서 이를 표시한다. 반공변성(contravariant) 공변성의 반대 - 자기 자신과 부모 객체만 허용한다. Java 에서의 와 같다. Kotlin 에서는 in 키워드를 사용해서 표현한다. 매개변수화 타입은 불공변이다 즉 서로 다른 타입 Type1과 Type2가 있을때 List은 List의 하위 타입도 상위 타입도 아니다 ex) List은.. 2023. 2. 15.
[이펙티브자바]item 30.이왕이면 제네릭 메서드로 만들라. 매개변수화 타입을 받는 정적 유틸리티 메서드 한정적 와일드 카드 타입(아이템31)을 사용하여 더 유연하게 개선할 수 있다. 제네릭 싱글턴 팩터리 제네릭은 런타임에 타입 정보가 소거(아이템28)되므로 하나의 객체를 어떤 타입으로든 매개변수화할 수 있다. 재귀적 타입 한정 자기 자신이 들어간 표현식을 사용하여 타입 매개변수의 허용 범위를 한정한다. 2023. 2. 14.
[이펙티브자바]item 29.이왕이면 제네릭 타입으로 만들라. 배열을 사용하는 코드를 제네릭으로 만들때 해결 책 두가지가 있다. 첫번째 방법은 제네릭 배열 대신에 Object 배열을 생성한 뒤에 제네릭 배열로 형변환 하는것. 형변환을 배열 생성시 한 번만 한다. 가독성이 좋다. 힙 오염이 발생할 수 있다(아이템31) 두번째 방법은 elements 필드의 타입을 E[] 에서 Object[]로 바꾸는 것이다. 제네릭 배열 대신에 Object 배열을 사용하고, 배열이 반환한 원소를 E로 형변환 하는것. 원소를 꺼낼때 마다 형변환을 해주어야 한다. 필요에 따라 한정적 타입 매개변수를 이용해서 제약조건을 추가하자. E extends Number> 같은.. 2023. 2. 13.
[이펙티브자바]item 28.배열보다는 리스트를 사용하라. 배열은 불안정 할 수 있다. 배열과 제네릭에는 매우 다른 타입 규칙이 적용된다. 배열은 공변이고 실체화되는 반면, 제네릭은 불공변이고 타입 정보도 소거된다. 둘을 섞어 쓰다가 컴파일 오류나 경고를 만나면, 가장 먼저 배열을 리스트로 대체하는 방법을 적용해보자. //공변 Object[] objects = new Long[1]; objects[0] = "타입이 달라 넣을 수 없다."; //불공변 List o1 = new ArrayList(); //호환되지 않는 타입이다. o1.add("타입이 달라 넣을 수 없다."); 배열은 런타임때 에러가 발생하고, 리스트를 사용하면 컴파일 시 바로 알 수 있다. 제네렉은 타입 정보가 런타임에는 소거된다. 이는 자바 5버전 이전의 하위호환 떄문에 컴파일러가 List 이라는.. 2023. 2. 11.
[이펙티브자바]item 27.비검사 경고를 제거하라 잠재적 위험이 될 수 있는 경고를 제거하는게 좋다. 경고를 제거할 수는 업지만 타입이 안전하다고 확신할 수 있다면 @SuppressWarnings("unchecked") 를사용하자 해당 어노테이션을 사용했다면 해당 경고를 무시해도 안전한 이유를 주석으로 남겨야 한다. 최대한 좁은 범위로 한정하자.상위에 넣으면 하위의 모든 경고가 무시되기 때문에, 추후 누군가가 경고가 될만한 코드를 넣어도 무시된다. public class SuppressWarning { Object[] elementData; private int size; public T[] toArray(T[] a) { if (a.length < size) { @SuppressWarnings("unchecked") T[] result = (T[]) A.. 2023. 2. 10.
[이펙티브자바]item 26.로 타입은 사용하지 말라 로(raw)타입을 사용하면 런타임에 예외가 일어날 수 있으니 사용하면 안 된다. 로 타입은 제네릭이 도입되기 이전 코드와의 호환성을 위해 제공될 뿐이다. 로 타입이란 제네릭 타입에서 타입 매개변수를 전혀 사용하지 않을 때를 말한다 ex)List, Set 로 타입을 쓰면 제네릭이 안겨주는 안정성과 표현력을 모두 잃게 된다. 애초에 왜 만들어놓은 걸까?: 이전 버전의 코드들의 호환성 때문이다. 비한정적 와일드카드 타입: => 타입이 안전하다. 아래는 로타입으로 일어날 수 있는 안정성 예제이다. public class Numbers { static int numElementsInCommon(Set s1, Set s2) { //한정적 와일드카드 타입으로 인한 add 불가능. //s1.add(**) int res.. 2023. 2. 10.
[이펙티브자바]item 25.톱레벨 클래스는 한 파일에 하나만 담으라. 소스파일 하나에 톱레벨 클래스를 여러개 선언하더라도 컴파일 된다. 하지만 같은 클래를 컴파일하거나, 설령 컴파일이 됐다하더라도, 컴파일러가 읽는 순서에 따라 동작이 달라질 수 있는 위험이 있다. 이를 해결하기 위해. 서로 다른 소스 파일로 분리하고 굳이 여러 톱레벨 클래스를 한파일에 담고 싶다면, 정적 멤버 클래스(아이템24)를 사용하는 방법을 고민해 보자. 교훈: 소스 파일 하나에는 반드시 톱레벨 클래스(혹은 톱레벨 인터페이스)를 하나만 담자 2023. 2. 8.
728x90