본문 바로가기

독후감/Effective Java

(10)
10. equals는 규칙에 맞게 재정의하라 equals 메서드는 재정의하기 쉬워 보이지만 사실 문제가 많다. 문제를 회피하는 가장 쉬운 길은 아예 재정의하지 않는 것이다. 클래스에 equals를 정의하지 않는다면 그 클래스의 인스턴스는 오직 자기 자신과만 같게된다. 그러니 다음에서 열거한 상황 중 하나에 해당한다면 재정의하지 않는 것이 최선이다. 각 인스턴스가 본질적으로 고유해야 한다. 인스턴스의 동등성을 검사할 필요가 없다. 상위 클래스에서 재정의한 equals가 하위 클래스에도 딱 들어맞는다. 클래스가 private이거나 package-private이고, equals를 호출할 일이 없다. 만약 equals메서드에 대한 실수를 좀 더 철저히 막고 싶다면 @Override public boolean equals(Object o) { throw n..
9. try-finally 보다는 try-with-resources를 사용하라 자바 라이브러리에는 close메서드를 활용해 직접 닫아줘야 하는 자원이 많다. 이런 경우 자바에서는 전통적으로 try-finally가 사용되었다. 하지만 try-finally는 닫아줘야하는 자원이 2개만 되어도 굉장히 난잡해진다. static void copy(String src, String dst) throws IOException { InputStream in = new FileInputStream(src); try { OutputStream out = new FileOutputStream(dst); try { byte[] buf = new byte[BUFFER_SIZE]; int n; while((n = in.read(buf)) >= 0) out.write(buf, 0, n); } finally ..
8. finalizer와 cleaner 사용을 피하라
7. 다 쓴 객체 참조를 해제하라 자바같은 가비지 컬렉션을 가진 언어에서는 메모리 누수를 찾기가 매우 어렵다.객체 참조를 하나라도 살려두면 가비지 컬렉터는 그 객체뿐 아니라 그 객체가 참조하는 모든 객체를 회수하지 못 한다. 이를 해결하는 방법은 간단하다. 해당 참조를 다 썻을 때 null 처리 해주면 된다. public class Stack { private Object[] elements; private int size = 0; private static final int DEFAULT_INITIAL_CAPACITY = 16; public Stack() { this.elements = new Object[DEFAULT_INITIAL_CAPACITY]; } public void push(Object e) { this.ensureCapa..
6. 불필요한 객체 생성을 피하라 다음은 정규표현식을 활용한 예제이다. static boolean isRomanNumera(String s) { return s.matches("^(?-.)M* ....; } 성능을 개선하려면 필요한 인스턴스를 클래스 초기화과정에서 생성해 캐싱하여, 나중에 해당 인스턴스를 재사용한다.이 방식은 쉬운 방식이지만 성능이 중요한 곳에서는 반복적으로 사용하기 적합치 않다. 이 메서드가 내부에서 만드는 인스턴스는 한 번 쓰이고 버려져 곧바로 가비지 컬렉션 대상이 된다. public class RomanNumerals { private static final Pattern ROMAN = Patterm.compile( "^(?-.)M* .... ); static boolean isRomanNumeral(String s..
5. 자원을 직접 명시하지 말고 의존 객체 주입을 사용하라 사용하는 자원에 따라 동작이 달라지는 클래스에는 정적 유틸리티 클래스나 싱글턴 방식이 적합하지 않다. public class SpellChecker { // 유연하지 않고 테스트하기 어렵다. private final Lexicon dictionary = ...; public SpellChecker(Lexicon dictionary) { this.dictionary = Objects.requireNonNull(dictionary); } }​ 클래스가 여러 자원 인스턴스를 지원해야 하며, 클라이언트가 원하는 자원을 사용해야 한다. 이 조건을 만족하는 패턴이 있으니, 바로 인스턴스를 생성할 때 생성자에 필요한 자원을 넘겨주는 방식이다. public class SpellChecker { // 유연하지 않고 테스..
4. 인스턴스화를 막으려거든 private 생성자를 사용하라 가끔 정적 메서드와 정적 필드만을 담은 클래스가 필요할 경우가 있다. 유틸리티 클래스를 만들 때 주로 사용되는데, 이런 클래스들은 인스턴스화 되는 것을 되도록 막아야 한다. 자바에서는 생성자를 개발자가 작성하지 않아도, 내부적으로 생성자를 제공해준다. 그렇기에 이를 막기 위해서는 private로 생성자를 임의로 명시해주는 것이 좋다. 또한 이 방식은 상속을 불가능하게 만든다. 상속을 받으려면 해당 부모 클래스의 생성자를 호출할 수 있어야 하는데, private 선언을 통해 부모 클래스를 상속할 길이 막혀버린다. public class Utility { private Utility() { throw new AssertionError(); } } 결론 유틸리티 클래스들을 정적 메서드로 채우게 된다면 생성자는..
3. private 생성자나 열거 타입으로 싱글턴임을 보증하라 싱글턴(singleton)이란 인스턴스를 오직 하나만 생성할 수 있는 클래스이다. 싱글턴을 만드는 방식은 둘 중 하나다. 두 방식 모두 private으로 감추고, 인스턴스에 접근할 수 있는 수단으로 public static 멤버를 하나 만든다. public class Elvis { public static final Elvis INSTANCE = new Elvis(); private Elvis() {...} public void leaveTheBuilding() {...} } 생성자는 INSTANCE 를 초기화할 때 한 번만 호출된다. 그렇기에 전체 시스템에서 해당 클래스는 하나만 생성됨을 보장할 수 있게된다.(단 향후 배울 리플랙션에서 private 생성자를 호출하는 법을 알게된다.) 해당 코드의 장점..