아이템 11 : equals를 재정의하거든 hasCode도 재정의하라 equales를 재정의한 모든 클래스에서 hashCode도 재정의해야 한다. 다음은 Object 명세에서 발췌한 규약이다. equals 비교에 사용되는 정보가 변경되지 않았다면, 애플리케이션이 실행되는 동안 그 객체의 hashCode 메서드는 몇 번을 호출해도 일관되게 항상 같은 값을 반환해야 한다. 단, 애플리케이션을 다시 실행한다면 이 값이 달라져도 상관없다. equals(Object)가 두 객체를 같다고 판단했다면, 두 객체의 hashCode는 똑같은 값을 반환해야 한다. equals(Object)가 두 객체를 다르다고 판단했더라도, 두 객체의 hashCode가 서로 다른 값을 반환할 필요는 없다, 단, 다른 객체에 대해서는 다른..
아이템 10 : equals는 일반 규약을 지켜 재정의하라 equals 메서드는 재정의하기 쉬워 보이지만 곳곳에 함정이 도사리고 있어서 자칫하면 끔찍한 결과를 초래한다. 다음 상황 중 하나에 해당한다면 재정의하지 않는 것이 최선이다. 각 인스턴스가 본질적으로 고유하다 인스턴스의 '논리적 동치성'을 검사할 일이 없다. 상위 클래스에서 재정의한 equals가 하위 클래스에도 딱 들어맞는다. 클래스가 private이거나 package-private이고 equals 메서드를 호출할 일이 없다. 그렇다면 equals를 재정의해야 할 때는 언제일까? 객체 식별성이 아니라 논리적 동치성을 확인해야 하는데, 상위 클래스의 equals가 논리적 동치성을 비교하도록 재정의되지 않았을 때다. 주로 값 클래스들이 여기 해당한..
아이템 9 : try-finally보다는 try-with-resources를 사용하라 자바 라이브러리에는 close 메서드를 호출해 직접 닫아줘야 하는 자원이 많다. 전통적으로 자원이 제대로 닫힘을 보장하는 수단으로 try-finally가 쓰였다. 예외가 발생하거나 메서드에서 반환되는 경우을 포함해서 말이다. 자원이 둘 이상이면 try-finally 방식은 너무 지저분해진다. try-with-resources를 사용하면 복수의 자원을 효율적으로 처리할 수 있다. 핵심 정리 꼭 회수해야 하는 자원을 다룰 때는 try-finally 말고, try-with-resources를 사용하자. 예외는 없다. 코드는 더 짧고 분명해지고, 만들어지는 예외 정보도 훨씬 유용하다. try-finally로 작성하면 실용적이지..
아이템 8 : finalizer와 cleaner 사용을 피하라 자바는 두 가지 객체 소멸자를 제공한다. 그중 finalizer는 예측할 수 없고, 상황에 따라 위험할 수 있어 일반적으로 불필요하다. cleaner는 finalizer보다는 덜 위험하지만, 여전히 예측할 수 없고, 느리고, 일반적으로 불필요하다. finalizer와 cleaner는 즉시 수행된다는 보장이 없다. 객체에 접근 할 수 없게 된 후 finalizer와 cleaner가 실행되기까지 얼마나 걸릴지 알 수 없다. 즉, finalizer와 cleaner로는 제때 실행되어야 하는 작업은 절대 할 수 없다. 자바 언어 명세는 finalizer나 cleaner의 수행 시점뿐 아니라 수행 여부조차 보장하지 않는다. 접근할 수 없는 일부 객체에 ..
아이템 7 : 다 쓴 객체 참조를 해제하라 가비지 컬렉션 언어에서는 의도치 않게 객체를 살려두는 메모리 누수를 찾기가 아주 까다롭다. 객체 참조 하나를 살려두면 가비지 컬렉터는 그 객체뿐 아니라 그 객체가 참조하는 모든 객체(그리고 또 그 객체들이 참조하는 모든 객체...)를 회수해가지 못한다. 그래서 단 몇개의 객체가 매우 많은 객체를 회수되지 못하게 할 수 있고 잠재적으로 성능에 악영향을 줄 수 있다. 해법은 간단하다. 해당 참조를 다 썼을 때 null 처리(참조 해제)하면 된다. 다 쓴 참조를 null 처리하면 다른 이점도 따라온다. 만약 null 처리한 참조를 실수로 사용하려 하면 프로그램은 즉시 NullPointerException을 던지며 종료된다. 단, 객체 참조를 null 처리하는 일은 예..
아이템 6 : 불필요한 객체 생성을 피하라 똑같은 기능의 객체를 매번 생성하기보다는 객체 하나를 재사용하는 편이 나을 때가 많다. 재사용은 빠르고 세련되다. 특히 불변 객체는 언제든 재사용할 수 있다. 생성자 대신 정적 팩터리 매서드를 제공하는 불변 클래스에서는 정적 팩터리 메서드를 사용해 불필요한 객체 생성을 피할 수 있다. 예컨대 Boolean(String) 생성자 대신 Boolean.valueOf(String) 팩터리 메서드를 사용하는 것이 좋다. 생성자는 호출할 때마다 새로운 객체를 만들지만, 팩터리 메서드는 전혀 그렇지 않다. 불변 객체만이 아니라 가변 객체라 해도 사용 중에 변경되지 않을 것임을 안다면 재사용할 수 있다. 생성 비용이 아주 비싼 객체도 더러 있다. 이런 '비싼 객체'가 반복해서..
아이템 5 : 자원을 직접 명시하지 말고 의존 객체 주입을 사용하라 사용하는 자원에 따라 동작이 달라지는 클래스에는 정적 유틸리티 클래스나 싱글턴 방식이 적합하지 않다. 클래스가 여러 자원 인스턴스를 지원해야 하며, 클라이언트가 원하는 자원을 사용해야 하는 조건에 만족하는 간단한 패턴이 있다. 인스턴스를 생성할 때 생성자에 필요한 자원을 넘겨주는 방식이다. 이를 의존 객체 주입 패턴이라고 한다. 아래 코드를 통해 알아보자. 1 2 3 4 5 6 7 8 9 10 public class SpellChecker{ private final Lexicon dictionary; public SpellChecker(Lexicon dictionary){ this.dictionary = objects.requireNon..
아이템 4 : 인스턴스화를 막으려거든 private 생성자를 사용하라 이따금 단순히 정적 메서드와 정적 필드만을 담은 클래스를 만들고 싶을 때가 있을 것이다. 객체 지향적으로 사고하지 않는 이들이 종종 남용하는 방식이기에 그리 곱게 보이지는 않지만, 분명 나름의 쓰임새가 있다. 기본 타입 값이나 배열 관련 메서드들을 모아놓을 수 있다. 특정 인터페이스를 구현하는 객체를 생성해주는 정적 메서드를 모아놓을 수도 있다. final 클래스와 관련한 메서드들을 모아놓을 때도 사용한다. 정적 멤버만 담은 유틸리티 클래스는 인스턴스로 만들어 쓰려고 설계한게 아니다. 하지만 생성자를 명시하지 않으면 컴파일러가 자동으로 기본 생성자를 만든다. 이러한 사태를 막으려고 추상 클래스를 만드는건 어떨까? 라고 생각할 수도 있다..
아이템 3 : private 생성자나 열거 타입으로 싱글턴임을 보증하라 싱글턴이란 인스턴스를 오직 하나만 생성할 수 있는 클래스를 말한다. 클래스를 싱글턴으로 만들면 이를 사용하는 클라이언트를 테스트하기가 어려워질 수 있다. 싱글턴을 만드는 방식은 보통 둘 중 하나다. 두 방식 모두 생성자는 private으로 감춰두고, 유일한 인스턴스에 접근할 수 있는 수단으로 public static 멤버를 하나 마련해둔다. 우선 public static 멤버가 final 필드인 방식을 살펴보자. 1 2 3 4 5 6 public class Elvis{ public static final Elvis INSTANCE = new Elvis(); private Elvis() { ... } public void leaveTh..
아이템 2 : 생성자에 매개변수가 많다면 빌더를 고려하라 정적 팩터리와 생성자에는 똑같은 제약이 하나 있다. 선택적 매개변수가 많을 때 적절히 대응하기 어렵다는 점이다. 이런 클래스용 생성자 혹은 정적 팩터리는 어떤 모습일까? 프로그래머들은 이럴 때 점층적 생성자 패턴을 즐겨 사용했다. 필수 매개변수만 받는 생성자, 필수 매개변수와 선택 매개변수 1개를 받는 생성자, ... 형태로 선택 매개변수를 전부 다 받는 생성자까지 늘려가는 방식이다. 매개변수가 많더라도 점층적 생성자 패턴도 쓸 수는 있지만, 매개변수 개수가 많아지면 클라이언트 코드를 작성하거나 읽기가 어려워진다. 선택 매개변수가 많을 때 활용할 수 있는 다른 대안이 있다. 바로 자바빈즈 패턴이다. 매개변수가 없는 생성자로 객체를 만든 후, 세터 ..