이펙티브자바

    [Effective Java] 적시에 방어적 복사본을 만들라

    방어적 프로그래밍 자바는 안전한 언어이지만, 다른 클래스로부터의 침범을 다 막을 수 있는 건 아니다. 따라서 클라이언트가 불변식을 깨뜨리려 혈안이 되어 있다고 가정하고 방어적으로 프로그래밍해야 한다. 불변식을 지키지 못한 예시 public final class Period { private final Date start; private final Date end; public Date start() { return start; } public Date end() { return end; } } 다음 코드는 불변같지만, Date가 가변이라는 사실을 이용하면 어렵지 않게 그 불변식을 깨뜨릴 수 있다. Date start = new Date(); Date end = new Date(); Period p = n..

    [Effective Java] 표준 함수형 인터페이스를 사용하라

    java.util.function 패키지에는 다양한 용도의 표준 함수형 인터페이스가 담겨 있다. 기억해야 할 함수형 인터페이스 6개 Operator 인터페이스 - 반환값과 인수의 타입이 같은 함수 인수가 1개인 UnaryOperator 인수가 2개인 BinaryOperator T apply(T t) String::toLoswerCase T apply(T t1, T t2) BigInteger::add Predicate 인터페이스 - 인수 하나를 받아 boolean을 반환하는 함수 boolean test(T t) Collection::isEmpty Function 인터페이스 - 인수와 반환 타입이 다른 함수 R apply(T t) Arrays::asList Supplier 인터페이스 - 인수를 받지 않고 값..

    [Effective Java] 익명 클래스보다는 람다를 사용하라

    익명 클래스의 등장 예전에는 자바에서 함수 타입을 표현할 때 추상 메서드를 하나만 담은 인터페이스를 사용했다. 이런 인터페이스의 인스턴스를 함수 객체라고 하여, 특정 함수나 동작을 나타내는 데 썼다. 이런 익명 클래스는 이후에 함수 객체를 만드는 주요 수단이 되었다. Collections.sort(words, new Comparator() { public int compare(String s1, String s2) { return Integer.compare(s1.length(), s2.length()); } } 이런 익명 클래스 방식은 코드가 너무 길기 때문에 자바는 함수형 프로그래밍에 적합하지 않다. 람다식 자바 8부터 추상 메서드 하나짜리 인터페이스는 특별한 의미를 인정받아 인스턴스를 람다식을 사용..

    [Effective Java] 명명 패턴보다 애너테이션을 사용하라

    [Effective Java] 명명 패턴보다 애너테이션을 사용하라

    명명 패턴 특별히 다뤄야 할 프로그램 요소에는 구분되는 명명패턴을 이용했다. 예를 들어 JUnit은 테스트 메서드 이름이 test로 시작하게끔 했었다. 이런 명명 패턴은 다음과 같은 문제가 있다. 타입 세이프 하지 않다. tsetSaftey라고 적으면 JUnit은 이를 인지하지 못한다. 올바른 프로그램 요소에서만 사용된다는 보장이 없다. -> 클래스의 이름에 test를 붙여도 클래스에는 적용되지 않는다. 프로그램 요소를 매개변수로 전달할 방법이 없다. -> 예외 테스트가 힘들다. 애너테이션 @Retention가 @Target이라는 메타 어노테이션을 이용해 애너테이션의 라이프사이클을 지정하고 사용자가 올바른 프로그램 요소에 사용할 수 있도록 도와준다. 이러한 마커 애너테이션은 잘못 사용하면 컴파일 타임에 ..

    [Effective Java] ordinal 인덱싱 대신 EnumMap을 사용하라

    ordinal의 잘못된 사용 이따금 배열이나 리스트에서 원소를 꺼낼 때 ordinal 메서드로 인덱스를 얻는 코드가 있다. public class Plant { enum LifeCycle { ANNUAL, PERENNIAL, BIENNIAL } final String name; final LifeCycle lifeCycle; public Plant(String name, LifeCycle lifeCycle) { this.name = name; this.lifeCycle = lifeCycle; } @Override public String toString() { return name; } } public class Client { public static void main(String[] args) { S..