독후감/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 생성자를 호출하는 법을 알게된다.) 해당 코드의 장점.. 이전 1 2 다음