메서드나 생성자를 작성할 때면 매개변수에 어떤 제약이 있을지 생각해야 한다.
그 제약들을 문서화하고, 메서드 코드 시작부에서 명시적으로 검사해야 한다.
그렇게 매개변수 오류를 걸러내도록 해야 한다.
■ 매개변수가 유효한지 확인하라
API 사용자가 제약을 지킬 가능성을 크게 높일 수 있다.
다음은 전형적인 예다.
/**
* (현재 값 mod n) 값을 반환한다. 이 메세드는
* 항상 음이 아닌 BigInteger를 반환한다는 점에서 remainder 메서드와 다르다.
*
* @param m 계수 (양수여야 한다.)
* @return 현재 값 mod m
* @throws ArithmeticException m이 0보다 작거나 같으면 발생한다.
*/
public BigInteger mod(BigInteger m) {
if (m.signum() <= 0)
throw new ArithemeticException("계수(m)는 양수여야 합니다. " + m);
... // 계산 수행
}
[참고할 점]
- BigInteger 클래스 수준에서 기술한 주석이다.
- 그러므로 Biginteger 타입이어야 할 파라미터 m이 null인 것에 대한 NullPointerException에 대한 주석은 작성하지 않는다.
- 그럴 때는 자바의 null 검사 기능을 사용 가능하다.
■ 자바의 null 검사 기능
★ java.util.Objects.requireNonNull
// 자바의 null 검사 메서드!
// 유연하고 사용하기 편하다!
// 순수한 null 검사 목적으로 사용하면 된다!
this.strategy = Objects.requireNonNull(strategy, "전략");
// ∨ 이 메서드는...
// │ 입력을 그대로 반환한다. 값을 사용하는 동시에 null 검사 수행 가능하다.
// │ 아니면 순수한 null 검사 목적으로 사용해도 좋다.
■ assert문
- 핵심: assert한 조건이 무조건 참이라고 선언한다.
- private 메서드에서는 assert를 사용하여 유효한 값만이 파라미터로 넘어옴을 보증하자.
private static void sort(long a[], int offset, int length) {
assert a != null;
assert offset >= 0 && offset <= a.length;
assert length >= 0 && length <= a.length - offset;
... // 계산 수행
}
assert문은 일반적인 유효성 검사와 다르다.
1. 실패하면 AssertionError를 던진다.
2. 기본적으로 JVM에서 assert 기능은 비활성 상태다: 런타임에 아무런 효과 없다.
└ 단, java -ea (--enableassertions 옵션 주면 런타임에 영함 줌)
■ 나중에 쓰려고 저장하는 매개변수의 유효성 검사
List에 매개변수 요소들을 저장한다고 하자.
메서드가 그 List의 요소를 직접 사용하지 않고 나중에 사용하려고 List를 구성하는 경우,
각 요소의 유효성은 특히 더 신경 써서 검사해야 한다.
검사하지 않으면 List의 요소를 언젠가 꺼내 쓰는 시점에 NullPointerException이 발생하는데, List를 어디서 가져왔는지 디버깅하기 괴로워진다. 이것은 "나중에 쓰려고 저장하는 매개변수의 유효성을 검사하라"는 원칙이다.
생성자를 떠올려보자. 이 원칙의 특수한 케이스임을 이해할 수 있다. (생성자 매개변수의 유효성 검사)
단, 효율성을 항상 생각하자. 강박적으로 유효성을 검사하지는 말자.
다음의 경우를 생각해볼까?
- 유효성 검사 비용이 지나치게 높은 경우
- 계산 과정에서 암묵적으로 검사가 수행될 경우
└ ex: Collections.sort(List) 가 있어서 ClassCastException이 던져질 수 있는 경우
└ 암묵적 검사에 너무 꽂히진 말자. '실패 원자성'을 해칠 수 있다. (작업 도중 예외가 발생해도, 기존 객체는 정상적으로 사용할 수 있어야 한다. 즉 호출된 메서드가 실패하더라도 해당 객체는 메서드 호출 전 상태를 유지해야 한다. 매개변수의 유효성 검사를 통해, 객체 내부 상태 변경 전 잠재적 예외 가능성을 체크해낼 수 있다.)
의문점:
1. 메서드가 public일 때는 자바의 null검사를 이용하고, private일 땐 assert를 사용하는 건가? 맞다면 왜 그렇지?
'JAVA > Effective Java' 카테고리의 다른 글
[이펙티브 자바] null이 아닌, 빈 컬렉션이나 배열을 반환하라 ─ 8장:메서드:Item54 (0) | 2023.10.18 |
---|---|
[이펙티브 자바] 가변인수는 신중히 사용하라 ─ 8장:메서드:Item53 (0) | 2023.10.18 |
[이펙티브 자바] 다중정의(오버로딩)는 신중히 사용하라 ─ 8장:메서드:Item52 (1) | 2023.10.17 |
[이펙티브 자바] 메서드 시그니처를 신중하게 설계하라 ─ 8장:메서드:Item51 (0) | 2023.10.17 |
[이펙티브 자바] 적시에 방어적 복사본을 만들라 ─ 8장:메서드:Item50 (1) | 2023.10.17 |