Effective Java 3E

    학습기록 - toString을 항상 재정의하라

    Object의 기본 toString 메서드가 우리가 작성한 클래스에 적합한 문자열을 반환하는 경우는 거의 없다. 이 메서드는 PhoneNumber@adbbd처럼 단순히 클래스_이름@16진수로_표시한_해시코드를 반환할 뿐이다. toString의 일반 규약에 따르면 '간결하면서 사람이 읽기 쉬운 형태의 유익한 정보'를 반환해야 한다. 따라서 위 방식보다 707-867-5309처럼 전화번호를 직접 알려주는 형태가 훨씬 유익한 정보를 담고 있다. 또한, toString의 규약은 "모든 하위 클래스에서 이 메서드를 재정의하라"라고 한다. equals와 hashCode 규약만큼 중요하진 않지만, toString을 잘 구현한 클래스는 사용하기에 훨씬 즐겁고, 그 클래스를 사용한 시스템은 디버깅하기 쉽다. toStri..

    학습기록 - equals를 재정의하려거든 hashCode도 재정의하라

    equals를 재정의한 클래스 모두에서 hashCode도 재정의해야 한다. 우선 hashCode란 무엇인가? 간단하게 얘기하면 객체를 식별하는 하나의 정수 값이다. hashCode도 재정의하지 않으면 hashCode 일반 규약을 어기게 되어 해당 클래스의 인스턴스를 HashMap이나 HashSet 같은 컬렉션의 원소로 사용할 때 문제를 일으킬 것이다. 다음은 Object 명세에서 발췌한 규약이다. equals 비교에 사용되는 정보가 변경되지 않았다면, 애플리케이션이 실행되는 동안 그 객체의 hashCode 메서드는 몇 번을 호출해도 일관되게 항상 같은 값을 반환해야 한다. 단, 애플리케이션을 다시 실행한다면 이 값이 달라져도 상관없다. equals(Object)가 두 객체를 같다고 판단했다면, 두 객체의..

    학습기록 - equals는 일반 규약을 지켜 재정의하라

    equals 메서드는 재정의하기 쉬워 보이지만 곳곳에 함정이 도사리고 있어서 자칫하면 끔찍한 결과를 초래한다. 문제를 회피하는 가장 쉬운 길은 아예 재정의하지 않는 것이다. 다음에서 열거한 상황 중 하나에 해당한다면 재정의하지 않는 것이 최선이다. 각 인스턴스가 본질적으로 고유하다. 값을 표현하는 게 아니라 동작하는 개체를 표현하는 클래스가 여기에 해당한다. Thread가 좋은 예로, Object의 equals 메서드는 이러한 클래스에 딱 맞게 구현되었다. 인스턴스의 '논리적 동치성(logical equality)'을 검사할 일이 없다. 예컨대 java.util.regex.Pattern은 equals를 재정의해서 두 Pattern의 인스턴스가 같은 정규표현식을 나타내는지를 검사하는, 즉 논리적 동치성을 ..

    학습기록 - try-finally 보다는 try-with-resources를 사용하라

    자바 라이브러리에는 close 메서드를 호출해 직접 닫아줘야 하는 자원이 많다. InputStream, OutputStream, java.sql.Connection 등이 좋은 예다. 자원 닫기는 클라이언트가 놓치기 쉬워서 예측할 수 없는 성능 문제로 이어지기도 한다. 전통적으로 자원이 제대로 닫힘을 보장하는 수단으로 try-finally가 쓰였다. 예외가 발생하거나 메서드에서 반환되는 경우를 포함해서 말이다. static String firstLineOfFile(String Path) throws IOException{ BufferedReader br = new BufferedReader(new FileReader(Path)); try{ return br.readLine(); } finally{ br.c..

    학습기록 - finalizer와 cleaner 사용을 피하라

    자바는 두 가지 객체 소멸자를 제공한다. 그 중 finalizer는 예측할 수 없고, 상황에 따라 위험할 수 있어 일반적으로 불필요하다. 때문에 finalizer는 특별한 경우가 아닌 이상 기본적으로 '쓰지 말아야' 한다. 그래서 자바 9에서는 finalizer를 사용 자제(deprecated) API로 지정하고 cleaner를 그 대안으로 소개했다. cleaner는 finalizer보다는 덜 위험하지만, 여전히 예측할 수 없고, 느리고, 일반적으로 불필요하다. 자바의 finalizer와 cleaner는 C++의 파괴자(destructor)와는 다른 개념이다. C++에서의 파괴자는 (생성자의 꼭 필요한 대척점으로) 특정 객체와 관련된 자원을 회수하는 보편적인 방법이다. 자바에서는 접근할 수 없게 된 객체..

    학습기록 - 다 쓴 객체 참조를 해제하라

    C, C++를 쓰다가 자바로 넘어오면서 자바의 가비지 컬렉터를 보면 훨씬 편안해진다. 다 쓴 객체를 알아서 회수해 가기 때문이다. 그래서 자칫 메모리 관리에 더 이상 신경을 쓰지 않아도 된다고 오해할 수 있다. 아래 스택을 간단히 구현한 코드를 보자. public class Stack{ private Object[] elements; private int size = 0; private static final int DEFAULT_INITIAL_CAPACITY = 16; public Stack(){ elements = new Obejct[DEFAULT_INITIAL_CAPACITY]; } public void push(Object e){ ensureCapacity(); elements[size++] = ..