본문 바로가기

책/Effective Java

메서드

매개변수가 유효한지 검사하라

 - 메서드나 생성자를 작성할 때 매개변수들에 어떤 제약이 있을지 생각하고 메서드 코드 시작 부분에서 명시적으로 검사해야 한다.

 - public과 protected 메서드는 매개변수 값이 잘못됐을 때 던지는 예외를 문서화해야 한다.

 - 자바 7에 추가된 java.util.Objects.requireNonNull 메서드는 유연하고 사용하기도 편하니, 더 이상 null 검사를 수동으로 하지 않아도 된다.

this.stratergy = Objects.requireNonNull(strategy, "전략");


적시에 방어적 복사본을 만들라

 - 클라이언트에서 불변식을 깨뜨리려고 한다고 가정하고 방어적으로 프로그래밍해야 한다.

 - Date는 낡은 API이니 새로운 코드를 작성할 때는 더 이상 사용하면 안된다. (LocalDateTime이나 ZonedDateTime을 사용하라.)

 - 생성자에서 받은 가변 매개변수 각각을 방어적으로 복사해야 한다.

 - 매개변수가 제3자에 의해 확장될 수 있는 타입이라면 방어적 복사본을 만들 때 clone을 사용해서는 안 된다.


메서드 시그니처를 신중히 설계하라

 - 메서드 이름을 신중히 짓자.

 - 편의 메서드를 너무 많이 만들지 말자. (확신이 서지 않으면 만들지 말자.)

 - 매개변수 목록은 짧게 유지하자. (같은 타입의 매개변수 여러개가 연달아 나오는 경우가 특히 해롭다.)

 - 매개변수의 타입으로는 클래스보다는 인터페이스가 더 낫다.

 - boolean보다는 원소 2개짜리 열거 타입이 낫다.


다중정의는 신중히 사용하라

 - 오버라이드한 메서드는 동적(런타임)으로 선택되고, 오버로드한 메서드는 정적(컴파일타임)으로 선택 된다.

 - 아래의 main 함수를 수행하면 "컬렉션" 만 세 번 출력 된다. (런타임에는 타입이 달라지지만 컴파일타임(for 문)에는 c는 항상 Cillection<?> 타입이다.)

public class ConllectionClassifier {

public static String classify(Set<?> s) {

return "집합";

}


public static String classify(List<?> lst) {

return "리스트";

}


public static String classify(Collection<?> c) {

return "컬렉션";

}


public static void main(String[] args) {

Collection<?>[] collections = {

new HashSet<String>(),

new ArrayList<String>(),

new HashMap<String, String>().values()

};


for (Collection<?> c : collections) {

System.out.println(classify(c));

}

}

}

 - 아래의 main 함수를 수행하면 "와인", "스파클링 와인", "샴페인" 이 출력 된다.

Class Wine {

String name() { return "와인"; }

}


Class SparklingWine extends Wine {

@Override String name() { return "스파클링 와인"; }

}


Class Champagne extends SparklingWine {

@Override String name() { return "샴페인"; }

}


public class Overriding {

public static void main(String[] args) {

List<Wine> wineList = List.of(new Wine(), new SparklingWine(), new Champagne());

for (Wine wine : wineList) {

System.out.println(wine.name());

}

}

}

 - 안전하고 보수적으로 가려면 매개변수 수가 같은 오버로딩한 메서드는 만들지 말자.

 - 메서드를 오버로딩할 때, 서로 다른 함수형 인터페이스라도 같은 위치의 인수로 받아서는 안 된다.


가변인수는 신중히 사용하라

 - 메서드를 정의할 때 필수 매개변수는 가변인수 앞에 두자.

 - 필수 매개변수를 포함하는 가변인수 (X)

static int min(int... args) {

if (args.length == 0) {

throw new IllegalArgumentException("인수가 1개 이상 필요합니다.");

}

int min = args[0];

...

}

 - 가변인수 앞에 필수 매개변수를 사용 (O)

static int min(int firstArg, int... args) {

int min = firstArg;

...

}


 - 가변인수를 사용할 때는 성능 문제까지 고려해야 한다. (가변인수는 배열을 생성해서 매개변수를 담는다.)

 - ex) 매개변수가 3개 이상인 경우에만 가변인수를 사용 

public void foo() { }

public void foo(int a1) { }

public void foo(int a1, int a2) { }

public void foo(int a1, int a2, int... rest) { }


null이 아닌, 빈 컬렉션이나 배열을 반환하라

 - null을 반환하는 API는 사용하기 어렵고 오류 처리 코드도 늘어난다. 그렇다고 성능이 좋은 것도 아니다.


Optional 반환은 신중히 하라

 - Optional을 반환하는 메서드는 절대 null을 반환하지 말자.

 - Collection, Stream, Array, Optional 같은 컨테이너 타입은 Optional로 감싸면 안 된다.

 - 박싱된 기본 타입을 담은 Optional을 반환하지 말자. (OptionalInt, OptionalLong ... 등을 사용하자.)

 - Optional을 컬렉션의 키, 값, 원소나 배열의 원소로 사용하지 말자. (반환값 이외의 용도로 쓰는 경우는 매우 드물다.)

 - Optional 반환은 성능 저하가 뒤따르니, 성능에 민감한 메서드라면 null이나 예외를 던지는 편이 나을 수 있다.


공개된 API 요소에는 항상 문서화 주석을 작성하라

 - 공개된 모든 클래스, 인터페이스, 메서드, 필드 선언에 문서화 주석을 달아야 한다.

 - 메서드용 문서화 주석에는 해당 메서드와 클라이언트 사이의 규약을 명료하게 기술해야 한다.

 - 한 클래스(혹은 인터페이스) 안에서 요약 설명이 똑같은 멤버(혹은 생성자)가 둘 이상이면 안 된다. (특히 오버로딩한 메서드가 있다면 특히 더 조심하자.)

 - 제네릭 타입이나 제네릭 메서드를 문서화할 때는 모든 타입 매개변수에 주석을 달아야 한다.

 - 열거 타입을 문서화할 때는 상수들에도 주석을 달아야 한다.

 - 애너테이션 타입을 문서화할 때는 멤버들에도 모두 주석을 달아야 한다.

 - 클래스 혹은 정적 메서드가 스레드 안전하든 그렇지 않든, 스레드 안전 수준을 반드시 API 설명에 포함해야 한다.

 

' > Effective Java' 카테고리의 다른 글

예외  (0) 2020.03.27
일반적인 프로그래밍 원칙  (0) 2020.03.26
람다와 스트림  (0) 2020.03.20
열거 타입과 애너테이션  (0) 2020.03.18
제네릭  (0) 2020.03.17