반응형
8장 메서드
아이템 49 - 매개변수가 유효한지 검사하라
- 메서드 몸체가 실행되기 전에 매개변수를 확인하면 잘못된 값이 넘어왔을 때 즉각적이고 깔끔한 방식으로 예외를 던질 수 있다.
- 자바 7에 추가된 java.util.requireNonNull 메서드는 유연하고 사용하기도 편하니, 더 이상 null 검사를 수동으로 하지 않아도 된다.
- 메서드나 생성자를 작성할 때 그 매개변수들에 어떤 제약이 있을지 생각해야 하고 그 제약들은 문서화하고 코드 시작 부분에서 명시적으로 검사해야 한다.
아이템 50 - 적시에 방어적 복사본을 만들라
- 클라이언트가 여러분의 불변식을 깨뜨리려 혈안이 되어 있다고 가정하고 방어적으로 프로그래밍해야 한다.
- 가변 필드를 생성자 매개변수로 받아 클래스 필드에 저장하는 경우 각각을 방어적으로 복사해야 한다.
- Date는 낡은 API이니 새로운 코드를 작성할 때는 더 이상 사용하면 안된다.
- 매개변수의 유효성 검사를 하기 전에 방어적 복사본을 만들고 이 복사본으로 유효성을 검사해야 한다.
- 매개변수가 제3자에 의해 확장될 수 있는 타입이라면 방어적 복사본을 만들 때 clone을 사용해서는 안 된다.
- 가변 필드를 반환하는 get 접근자 메서드에서는 가변 필드의 방어적 복사본을 반환하도록 해야 한다.
아이템 51 - 메서드 시그니처를 신중히 설계하라
메서드 이름을 신중히 짓자
이해할 수 있고 같은 패키지에 속한 다른 이름들과 일관되게 짓는 게 최우선 목표다.
편의 메서드를 너무 많이 만들지 말자
메서드가 너무 많으면 학습, 문서화, 테스트, 유지보수하기 어렵다.
매개변수 목록은 짧게 유지하자. 4개 이하가 좋다.
- 과하게 긴 매개변수 목록을 짧게 줄여주는 기술 세 가지
- 여러 메서드로 쪼갠다. (직교성을 높인다)
- 예) List 인터페이스에서 지정된 부분 범위의 부분리스트에서 인덱스를 찾는 메서드를 별도로 제공하지 않고 subList, indexOf를 제공한 것
- 매개변수 여러 개를 묶어주는 도우미 클래스를 만든다.
- 예) class Point { int x; int y; }
- 객체 생성에 사용한 빌더 패턴을 메서드 호출에 응용한다.
- 여러 메서드로 쪼갠다. (직교성을 높인다)
- 매개변수 타입으로는 클래스보다는 인터페이스가 더 낫다.
- boolean보다는 원소 2개짜리 열거 타입이 낫다.
아이템 52 - 다중정의는 신중히 사용하라
- 다중정의(overloading)은 어느 메서드를 호출할지가 컴파일타임에 정해진다. 재정의(override)한 메서드는 동적으로 선택되고, 다중정의한 메서드는 정적으로 선택된다.
- API 사용자가 매개변수를 넘기면서 어떤 다중정의 메서드가 호출될지를 모른다면 프로그램이 오동작하기 쉽다. 다중정의가 혼동을 일으키는 상황을 피해야 한다.
- 안전하고 보수적으로 가려면 매개변수 수가 같은 다중정의는 만들지 말자.
- 다중정의하는 대신 메서드 일므을 다르게 지어주는 방법이 있다.
- 다중정의된 메서드들이 함수형 인터페이스를 인수로 받을 때 비록 서로 다른 함수형 인터페이스라도 인수 위치가 같으면 혼란이 생긴다. 따라서 메서드를 다중정의할 때 서로 다른 함수형 인터페이스라도 같은 위치의 인수로 받아서는 안된다.
- 프로그래밍 언어가 다중정의를 허용한다고 해서 다중정의를 꼭 활용하란 뜻은 아니다.
아이템 53 - 가변인수는 신중히 사용하라
<인수가 1개 이상이어야하는 가변인수 메서드 - 잘못 구현한 예!>
static int min(int... args) {
if (args.length == 0) {
throw new IllegalArgumentException("인수가 1개 이상 필요합니다.");
}
int min = args[0];
for (int i = 1; i < args.length; i++) {
if (args[i] < min)
min = args[i];
return min;
}
}
- 가장 심각한 문제는 인수를 0개만 넣어 호출하면 런타임에 실패한다는 점. (코드도 지저분함) args 유효성 검사를 명시적으로 해야한다.
<인수가 1개 이상이어야할 때 가변인수를 제대로 사용하는 방법>
static int min(int firstArg, int... remainingArgs) {
int min = firstArgs;
for (int arg : remainingArgs)
if (arg < min)
min = arg;
return min;
}
성능에 민감한 경우
-
가변인수 메서드는 호출될 때마다 배열을 새로 하나 할당하고 초기화하여 성능이 민감한 경우 문제가 될 수 있다.
-
가변인수의 유연성이 필요할 때 선택할 수 있는 패턴
public void foo() { } public void foo(int a1) { } public void foo(int a1, int a2) { } public void foo(int a1, int a2, int a3) { } public void foo(int a1, int a2, int a3, int... rest) { }
아이템 54 - null이 아닌, 빈 컬렉션이나 배열을 반환하라
- 컬렉션이나 배열 같은 컨테이너가 비었을 때 null을 반환하는 메서드를 사용할 때면 항시 방어 코드를 넣어줘야 한다.
- 빈 컨테이너를 할당하는 데도 비용이 드니 null을 반환하는게 성능상 낫다는 주장도 있으나 틀린 주장이다.
- 이 정도의 성능 차이는 신경 쓸 수준이 못 된다.
- 빈 컬렉션과 배열을 굳이 새로 할당하지 않고도 반환할 수 있다.
- 빈 컬렉션 할당이 성능을 눈에 띄게 떨어뜨리는 방법
- Collections.emptyList, Collections.emptySet, Collections.emptyMap
- 배열을 쓸 대도 절대 null을 반환하지 말고 길이가 0인 배열을 반환하라.
아이템 55 - 옵셔널 반환은 신중히 하라
옵셔널의 장점
옵셔널을 반환하는 메서드는 예외를 던지는 메서드보다 유연하고 사용하기 쉬우며, null을 반환하는 메서드보다 오류 가능성이 작다.
옵셔널 사용 시 주의점
-
옵셔널을 반환하는 메서드에서는 절대 null을 반환하지 말자, 옵셔널을 도입한 취지를 완전히 무시하는 행위다.
-
반환값으로 옵셔널을 사용한다고 무조건 득이 되는 건 아니다. 컬렉션, 스트림, 배열, 옵셔널 같은 컨테이너 타입은 옵셔널로 감싸면 안된다.
옵셔널을 메서드 반환 타입으로 사용해야 하는 경우
결과가 없을 수 있으며 클라이언트가 이 상황을 특별하게 처리해야 하는 경우
-
박싱된 기본 타입을 담은 옵셔널을 반환하지 말고 int, long, double 전용 옵셔널 클래스인 OptionalInt, OptionalLong, OptionalDouble을 사용하자.
-
옵셔널을 컬렉션의 키, 값, 원소나 배열의 원소로 사용하는게 적절한 상황은 거의 없다.
아이템 56 - 공개된 API 요소에는 항상 문서화 주석을 작성하라
- API를 쓸모 있게 하려면 잘 작성된 문서도 곁들여야 한다.
- API를 올바로 문서화하려면 공개된 모든 클래스, 인터페이스, 메서드, 필드 선언에 문서화 주석을 달아야 한다.
- 메서드용 문서화 주석에는 해당 메서드와 클라이언트 사이의 규약을 명료하게 기술해야 한다.
- how가 아닌 what을 기술해야 한다.
- 자기사용 패턴은 자바 8에 추가된 @impleSpec 태그로 문서화한다.
- 열거 타입을 문서화할 때는 상수들에도 주석을 달아야 한다.
- 애너테이션 타입을 문서화할 때는 멤버들에도 모두 주석을 달아야 한다.
- 클래스 혹은 정적 메서드가 스레드 안전하든 아니든, 스레드 안전 수준을 반드시 API 설명에 포함해야 한다.
반응형
'개발 > 자바' 카테고리의 다른 글
sun.reflect.GeneratedMethodAccessor 클래스에 대해서 (0) | 2020.10.13 |
---|---|
자바 성능을 결정짓는 코딩 습관과 튜닝 이야기 (0) | 2020.06.09 |
Effective Java 3/E - 7장 람다와 스트림 요약정리 (0) | 2019.05.19 |
JSON 스키마 (0) | 2017.06.30 |
JSON STREAMING API (0) | 2017.06.30 |