Effective Java 3E

    학습기록 - 익명 클래스보다는 람다를 사용하라

    예전에는 자바에서 함수 타입을 표현할 때 추상 메서드를 하나만 담은 인터페이스(드물게는 추상 클래스)를 사용했다. 이런 인터페이스의 인스턴스를 함수 객체(function object)라고 하여, 특정 함수나 동작을 나타내는 데 썼다. 1997년 JDK 1.1이 등장하면서 함수 객체를 만드는 주요 수단은 익명 클래스가 되었다. 다음 코드를 예로 살펴보자. 문자열을 길이순으로 정렬하는데, 정렬을 위한 비교 함수로 익명 클래스를 사용한다. 1 2 3 4 5 Collections.sort(words, new Comparator(){ public int compare(String s1, String s2){ return Integer.compare(s1.length(), s2.length()); } }); Col..

    학습기록 - 정의하려는 것이 타입이라면 마커 인터페이스를 사용하라

    아무 메서드도 담고 있지 않고, 단지 자기 자신을 구현하는 클래스가 특정 속성을 가짐을 표시해 주는 인터페이스를 마커 인터페이스(marker interface)라 한다. Serializable 인터페이스가 가장 좋은 예다. Serializable은 자신을 구현한 클래스의 인스턴스는 ObjectOutputStream을 통해 쓸(write) 수 있다고, 즉 직렬화(serialization)할 수 있다고 알려준다. 마커 어노테이션이 등장하면서 마커 인터페이스는 구식이 되었다는 이야기를 들어봤을 것이다. 하지만 사실이 아니다. 마커 인터페이스는 두 가지 면에서 마커 어노테이션보다 낫다. 첫 번째, 마커 인터페이스는 이를 구현한 클래스의 인스턴스를 구분하는 타입으로 쓸 수 있으나, 마커 어노테이션은 그렇지 않다...

    학습기록 - @Override 어노테이션을 일관되게 사용하라

    자바가 기본으로 제공하는 어노테이션 중 보통의 프로그래머에게 가장 중요한 것은 @Override일 것이다. @Override는 메서드 선언에만 달 수 있으며, 이 어노테이션이 달렸다는 것은 상위 타입의 메서드를 재정의했음을 뜻한다. 이 어노테이션을 일관되게 사용하면 여러 가지 악명 높은 버그들을 예방해 준다. 다음의 Bigram을 살펴보자. 이 클래스는 바이그램, 즉 여기서는 영어 알파벳 2개로 구성된 문자열을 표현한다. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 import java.util.Set; public class Bigram{ private final char first; private final char second; p..

    학습기록 - 명명 패턴보다 애너테이션을 사용하라

    전통적으로 도구나 프레임워크가 특별히 다뤄야 할 프로그램 요소에는 딱 구분되는 명명 패턴을 적용했다. 예컨대 테스트 프레임워크인 JUnit은 버전 3까지 테스트 메서드 이름을 test로 시작하게끔 했다. 효과적인 방법이지만 단점도 크다. 첫 번째, 오타가 나면 안 된다. 실수로 이름을 tsetSafetyOverride로 지으면 JUnit 3은 이 메서드를 무시하고 지나치기 때문에 개발자는 이 테스트가 (실패하지 않았으니) 통과했다고 오해할 수 있다. 명명 패턴의 단점 두 번째는 올바른 프로그램 요소에서만 사용되리라 보증할 방법이 없다는 것이다. 예컨대 (메서드가 아닌) 클래스 이름을 TestSafetyMechanisms로 지어 JUnit에 던져줬다고 해보자. 개발자는 이 클래스에 정의된 테스트 메서드들을..

    학습기록 - 확장할 수 있는 열거 타입이 필요하면 인터페이스를 사용하라

    열거 타입은 거의 모든 상황에서 타입 안전 열거 패턴(typesafe enum pattern)보다 우수하다. 단, 예외가 하나 있으니, 타입 안전 열거 패턴은 확장할 수 있으나 열거 타입은 그럴 수 없다는 점이다. 달리 말하면, 타입 안전 열거 패턴은 열거한 값들을 그대로 가져온 다음 값을 더 추가하여 다른 목적으로 쓸 수 있는 반면, 열거 타입은 그렇게 할 수 없다는 뜻이다. 실수로 이렇게 설계한 것은 아니다. 사실 대부분 상황에서 열거 타입을 확장하는 건 좋지 않은 생각이다. 확장한 타입의 원소는 기반 타입의 원소로 취급하지만 그 반대는 성립하지 않는다면 이상하지 않은가! 기반 타입과 확장된 타입들의 원소 모두를 순회할 방법도 마땅치 않다. 마지막으로 확장성을 높이려면 고려할 요소가 늘어나 설계와 구..

    학습기록 - ordinal 인덱싱 대신 EnumMap을 사용하라

    이따금 배열이나 리스트에서 원소를 꺼낼 때 ordinal 메서드로 인덱스를 얻는 코드가 있다. 식물을 간단히 나타낸 다음 클래스를 예로 살펴보자. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 class Plant{ enum LifeCycle { ANNUAL, PERENNIAL, BIENNIAL } final String name; final LifeCycle lifeCycle; Plant(String name, LifeCycle lifeCycle){ this.name = name; this.lifeCycle = lifeCycle; } @Override public String toString(){ return name; } } Colored by Color Scripter cs 이제 ..