본문 바로가기

reviews/Effective JAVA

(13)
015. 클래스와 멤버의 접근 권한을 최소화하라 잘 설계된 컴포넌트는 모든 내부 구현을 완벽히 숨겨, 구현과 API를 깔끔히 분리한다. 소프트웨어 설계의 근간이 되는 정보 은닉, 캡슐화 개념을 구현해 오직 API를 통해서만 소통하며 서로의 내부 동작 방식에 개의치 않도록 해야 한다. 정보 은닉의 장점 여러 컴포넌트를 병렬로 개발할 수 있기 때문에 시스템 개발 속도를 높인다. 각 컴포넌트를 더 빨리 파악하여 디버깅할 수 있고 컴포넌트 교체의 부담이 적어 시스템 관리 비용을 낮춘다. 프로파일링을 통해 최적화가 필요한 컴포넌트를 쉽게 찾을 수 있고, 다른 컴포넌트에 성능을 주지 않고 최적화를 시도할 수 있다. (자체가 성능을 높여주진 않음) 소프트웨어 재사용성을 높인다. 개별 컴포넌트 별로 동작을 검증할 수 있어 큰 시스템을 제작하는 난이도를 낮춰준다. 접..
014. Comparable을 구현할지 고려하라 알파벳, 숫자, 연대 같이 순서가 명확한 값 클래스를 작성한다면 반드시 Comparable 인터페이스를 구현하라. public interface Comparable { int compareTo(T t); } compareTo는 Comparable 인터페이스의 유일무이한 메서드인데 equals와 유사하지만 Object의 메서드가 아니다. 단순 동치성 비교에 더해 순서까지 비교할 수 있으며 제네릭하다. compareTo 규약을 지키지 못하면 비교를 활용하는 클래스와 어울리지 못한다. : TreeSet TreeMap Collections Arrays Comparable 구현의 이점 Comparable을 구현한 클래스의 인스턴스들은 자연적인 순서가 있어 다음과 같이 간단히 정렬이 가능하다. Arrays.sort..
013. clone 재정의는 주의해서 진행하라 Cloneable은 복제해도 되는 클래스임을 명시하는 용도의 믹스인 인터페이스(mixin interface)이다. 인터페이스를 구현한다는 것은 일반적으로 해당 클래스가 그 인터페이스에서 정의한 기능을 제공한다고 선언하는 행위이지만, Cloneable의 경우에는 상위 클래스에 정의된 protected 메서드의 동작 방식을 변경한다. clone 메서드가 선언된 곳이 Cloneable이 아닌 Object이고, 그마저도 protected이다. 그래서 Cloneable을 구현하는 것만으로는 외부 객체에서 clone 메서드를 호출할 수 없다. 메서드 하나 없는 Cloneable 인터페이스는 대체 무슨 일을 할까? 이 인터페이스는 Object의 protected 메서드인 clone의 동작 방식을 결정한다. Clone..
012. toString을 항상 재정의하라 toString의 규약 : 모든 하위 클래스에서 이 메서드를 재정의하라. Object의 기본 toString 메서드는 단순히 클래스_이름@16인지루_표시한_해시코드를 반환한다. 규약에 따라 잘 구현한 클래스를 사용한 시스템은 디버깅하기 쉽다. ♦︎ toString을 제공할 이유가 없는 경우 정적 유틸리티 클래스 대부분의 열거 타입 : 자바가 이미 완벽한 toString을 제공한다. 예외 하위 클래스들이 공유해야 할 문자열 표현이 있는 추상 클래스 : 대다수의 컬렉션 구현체는 추상 컬렉션 클래스들의 toString 메서드를 상속해 쓴다. 👉 toString의 재정의 규약과 좋은 형태 간결하면서 사람이 읽기 쉬운 형태의 유익한 정보를 반환한다. 그 객체가 가진 주요 정보를 모두 반환하여 스스로를 완벽히 설명..
011. equals를 재정의하려거든 hashCode도 재정의하라 equals를 재정의한 클래스 모두에서 hashCode도 재정의해야 한다. 👉 Object 명세 equals 비교에 사용되는 정보가 변경되지 않았다면, 애플리케이션이 실행되는 동안 그 객체의 hashCode 메서드는 몇 번을 호출해도 일관되게 항상 같은 값을 반환해야 한다. equals(Object)가 두 객체를 같다고 판단했다면, 두 객체의 hashCode는 똑같은 값을 반환해야 한다. equals(Object)가 두 객체를 다르다고 판단했더라도, 두 객체의 hashCode가 서로 다른 값을 반환할 필요는 없다. 단, 다른 객체에 대해서는 다른 값을 반환해야 해시테이블의 성능이 좋아진다. 논리적으로 같은 객체는 같은 해시코드를 반환해야 한다. equals는 물리적으로 다른 두 객체를 논리적으로 같다고 ..
010. equals는 일반 규약을 지켜 재정의하라 ♦︎ equals()를 옳게 재정의해야 하는 이유 옳게 재정의 되지 않은 경우 프로그램이 이상하게 동작하거나 종료될 수 있고 원인을 찾기 힘들 수 있다. 컬렉션 클래스들을 포함해 수 많은 클래스는 전달받은 객체가 equals 규약을 지킨다고 가정하고 동작한다. /** CaseInsensitiveString.java * Object 명세에 적힌 규약 다섯가지.대칭성 예시 중.. */ (CaseInsensitiveString의 equals()를 규약에 맞게 수정하지 않은 경우) List list = new ArrayList(); list.add(caseInsensitiveString); System.out.println(list.contains(string)); ⇒ 위 경우 런타임 에러가 발생하거나 true..
009. try-finally보다는 try-with-resource를 사용하라 자바 라이브러리에는 close 메서드를 직접 호출해 닫아줘야 하는 자원들이 있다. ex) InputStream, OutputStream, java.sql.Connection 등 이런 자원 중 상당수가 안전망으로 finalizer를 활용하고는 있지만 그리 믿을만하지 못하기 때문에 클라이언트가 자원 닫기를 놓치는 경우 예측할 수 없는 성능 문제로 이어지기도 한다. 👉 전통적인 자원 닫기 방법 static String firstLineOfFile(String path) throws IOException { BufferedReader br = new BufferedReader(new FileReader(path)); try { return br.readLine(); } finally { br.close(); }..
007. 다 쓴 객체 참조를 해제하라 👉 메모리 누수 컴퓨터 프로그램이 필요하지 않은 메모리를 계속 점유하고 있는 현상을 말한다. ♦︎ 객체들의 다 쓴 참조 배열로 Stack 을 구현 /** StackMemoryLeak.java */ public class StackMemoryLeak { private Object[] elements; private int size = 0; private static final int DEFAULT_INITIAL_CAPACITY = 16; public StackMemoryLeak() { elements = new Object[DEFAULT_INITIAL_CAPACITY]; } public void push(Object e) { ensureCapacity(); elements[size++] = e; } pub..