이펙티브 자바 28

제네릭을 활용한 열거 타입 예제

한정적 타입 토큰 & Operation>자바 제네릭스 문법에서 사용되는 상한 경계(bound) 지정 구문이다.이 구문은 제네릭 타입 T가 두 가지 조건을 모두 만족해야 함을 나타낸다:Enum의 서브타입이어야 한다.Operation 인터페이스를 구현해야 한다.이 구문을 사용하면 T는 반드시 열거형(enum)이면서 동시에 Operation 인터페이스를 구현한 타입이어야 한다.이를 통해 열거형 타입에 대한 제네릭 클래스나 메서드를 정의하면서도, 해당 타입이 특정 인터페이스를 구현하도록 강제할 수 있다. Operation 인터페이스 정의public interface Operation { double apply(double x, double y);} Operation을 구현하는 Enum 정의public en..

ParameterizedTypeReference와 실체화 불가 타입

ParameterizedTypeReference는 스프링 프레임워크에서 제공하는 클래스로, 제네릭 타입을 갖는 객체의 타입 정보를 보존하기 위한 목적으로 사용된다. 주로 제네릭 타입을 갖는 클래스나 메서드를 호출하고 그 결과를 가져올 때 사용된다.일반적으로 자바의 제네릭은 런타임에 소거되기 때문에, 제네릭 타입에 대한 정보를 동적으로 추출하기 어렵다.하지만 ParameterizedTypeReference를 사용하면 런타임에 제네릭 타입 정보를 유지할 수 있다. 사용 예시ParameterizedTypeReference를 사용하는 예시를 살펴보겠다.스프링의 RestTemplate을 사용하여 HTTP 요청을 보내고, 응답을 받을 때 제네릭 타입을 유지하고 싶은 경우에 사용할 수 있다. import org.sp..

아이템 31 한정적 와일드카드를 사용해 API 유연성을 높여라

// E 생산자(producer) 매개변수에 와일드카드 타입 적용public void pushAll(Iterable src) { for (E e : src) push(e);}// E 소비자(consumer) 매개변수에 와일드카드 타입 적용public void popAll(Collection(? super E) dst) { while (!isEmpty()) dst.add(pop());} Stack 클래스의 메소드를 한정적 와일드카드를 사용해 구현했다.간단한 예제지만, 헷갈리는 부분들을 분명하게 공부하고 넘어가고자 한다. 제네릭에서의 생산자(producer)와 소비자(consumer)생산자(producer) 생산자는 데이터를 "생산"하여 제공하는 역할을 한다. 즉, 컬렉션이나 객체로부터 데이터를 추출하거나 ..

아이템 13 clone 재정의는 주의해서 진행하라

자바에서 Object 클래스의 clone() 메서드는 해당 객체를 복제하는데 사용된다. 그러나, Object 클래스의 clone() 메서드는 복제될 객체가 Cloneable 인터페이스를 구현하고 있지 않으면 'CloneNotSupportedException'을 던진다. 즉, 해당 객체가 clone() 메서드를 구현하기 위해서는 Cloneable을 implements 해야한다. 그런데, Cloneable을 구현하는 것만으로는 외부 객체에서 clone 메서드를 호출할 수 없다. 왜냐하면, Cloneable은 인터페이스 자체가 메서드를 갖지 않는 마커 인터페이스이기 때문이다. 마커 인터페이스란? 메서드를 갖지 않는 인터페이스로, 해당 인터페이스를 구현한 클래스가 특정한 특성이나 동작을 갖고 있음을 나타낸다. ..

아이템 12 toString을 항상 재정의하라

Object의 기본 toString 메서드는 '클래스_이름@16진수로_표시한_해시코드' (ex: PhoneNumber@adbbd)같은 형식을 반환한다. toString 메서드는 객체를 println, printf, 문자열 연결 연산자(+), assert 구문에 넘길 때, 혹은 디버거가 객체를 출력할 때 자동으로 불린다. toString은 해당 객체에 관한 명확하고 유용한 정보를 읽기 좋은 형태로 반환해야 한다.

아이템 11 equals를 재정의하려거든 hashCode도 재정의하라

equals를 재정의한 클래스 모두에서 hashCode도 재정의해야 한다. 그렇지 않으면 hashCode 일반 규약을 어기게 되어 해당 클래스의 인스턴스를 HashMap이나 HashSet 같은 컬렉션의 원소로 사용할 때 문제를 일으킬 것이다. equals 비교에 사용되는 필드를 고려해서 논리적으로 동일한 객체끼리는 동일한 hashCode를 갖게 구현해야 한다. 전형적인 hashCode 메서드 @Override public int hashCode() { int result = Short.hashCode(areaCode); // 1 result = 31 * result + Short.hashCode(prefix); // 2 result = 31 * result + Short.hashCode(lineNum);..

아이템 10 equals는 일반 규약을 지켜 재정의하라

equals를 재정의 할 필요가 없는 상황 각 인스턴스가 본질적으로 고유하다. Object의 equals 메서드가 그렇다. 인스턴스의 '논리적 동치성(logical equality)'을 검사할 일이 없다. java.util.regex.Pattern의 equals같이 동일한 정규표현식을 나타내는지 같은 논리적 동일함을 판단할 필요가 없다면 Object의 equals를 그대로 받으면 된다. 상위 클래스에서 재정의한 equals가 하위 클래스에도 딱 들어맞는다. Set

아이템 9 try-finally 보다는 try-with-resources를 사용하라

자바 라이브러리에는 close 메서드를 호출해 직접 닫아줘야 하는 자원들이 있다. try-with-resources를 쓰면 AutoCloseable 또는 Closeable 인터페이스를 구현한 자원 객체들을 사용 후, 자동으로 close 하게 할 수 있다. 예시 import java.io.BufferedReader; import java.io.FileReader; import java.io.IOException; public class TryWithResourcesExample { public static void main(String[] args) { // 파일 경로 지정 String filePath = "example.txt"; // try-with-resources를 사용하여 BufferedReade..

아이템 8 finalizer와 cleaner 사용을 피하라

- 자바는 finalizer와 cleaner라는 두 가지 객체 소멸자를 제공한다. - finalizer는 예측할 수 없고, 상황에 따라 위험할 수 있어 일반적으로 불필요하다. (deprecated) - cleaner는 그 대안으로 소개되었지만 여전히 예측할 수 없고 느리고 일반적으로 불필요하다. finalizer와 cleaner를 쓰지 않아야 할 구체적인 이유 finalizer와 cleaner는 즉시 수행된다는 보장이 없다. 그래서 제때 실행되어야 하는 작업은 절대 할 수 없다. 자바 언어 명세는 어떤 스레드가 finalizer를 수행할지 명시하지 않았으니, 이 문제를 예방할 보편적인 해법은 finalizer를 사용하지 않는 방법뿐이다. cleaner는 자신을 수행할 스레드를 제어할 수 있다는 면에서 조..

아이템 7 다 쓴 객체 참조를 해제하라

가비지 컬렉션 언어에서는 (의도치 않게 객체를 살려두는) 메모리 누수를 찾기가 아주 까다롭다. 객체 참조 하나를 살려두면 가비지 컬렉터는 그 객체뿐 아니라 그 객체가 참조하는 모든 객체(그리고 또 그 객체들이 참조하는 모든 객체)를 회수해가지 못한다. 그래서 잠재적으로 성능에 악영향을 줄 수 있다. 해법 null 처리(참조 해제)하면 된다. 하지만 모든 객체를 다 쓰자마자 일일이 null 처리하는 것은 프로그램을 필요 이상으로 지저분하게 만들 뿐이다. 객체 참조를 null 처리하는 일은 예외적인 경우여야 한다. 더 좋은 해법 참조를 담은 변수를 유효 범위(scope) 밖으로 밀어내는 것이다. 나머지 메모리 누수 주범 캐시, 리스너, 콜백 역시 메모리 누수를 일으키는 주범이다. WeakHashMap의 를 ..