public과 protected 메서드는 매개변수 값이 잘못됐을 때 던지는 예외를 문서화해야 함
/**
* (현재 값 mod m) 값을 반환한다. 이 메서드는
* 항상 음이 아닌 BigInteger를 반환한다는 점에서 remainder 메서드와 다르다.
*
* @param m 계수 (양수여야 한다.)
* @return 현재 값 mod m
* @throws ArithmeticException m이 0보다 작거나 같으면 발생한다.
*/
public BigInteger mod(BigInteger m) {
if (m.signum() < 0)
throw new ArithmeticException("계수(m)는 양수여야 합니다. " + m);
...
}
requireNonNull 메서드
this.strategy = Objects.requireNonNull(strategy, "전략"); // 예외 메시지 지정
Objects 범위 검사 기능
checkFromIndexSize, checkFromToIndex, checkIndex 메서드
→ 예외 메시지를 지정할 수 없고 리스트와 배열전용으로 설계됨
단언문 (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;
...// 계산 수행
}
공개되지 않은 메서드라면, 패키지 제작자가 직접 메서드가 호출되는 상황을 통제할 수 있기 때문에 오직 유효한 값만이 메서드에 넘겨지리라는 것을 보증해야 함
실패시 AssertionError를 던짐
런타임에 아무런 효과도, 아무런 성능 저하도 없음
(assert는 디버깅 목적으로 사용됨)
메서드가 사용하지 않고 나중에 쓰기 위해 저장하는 매개변수는 더 신경 써서 검사해야 함
public class User {
private String email;
public void setEmail(String email) {
// 유효성 검사를 하지 않고 저장
this.email = email;
}
public void sendEmail() {
// 나중에 사용 시 무효한 값으로 인해 실패
System.out.println("Sending email to " + email.toLowerCase());
}
}
User user = new User();
user.setEmail(null); // 유효성 검사를 안 하면 null 저장
user.sendEmail(); // NullPointerException 발생
→ 클라이언트가 값을 사용하려할 때 에러가 발생함 → 원인을 추적하기 어려워짐
메서드 몸체 실행 전에 매개변수 유효성을 검사해야 한다는 규칙에 예외가 있음
유효성 검사 비용이 지나치게 높거나 실용적이지 않은 경우
계산 과정에서 암묵적으로 검사가 수행되는 경우
ex) Collections.sort(List)
처럼 정렬 과정에서 비교가 이루어짐 → null이 포함되어 있으면 NullPointException 발생
→ 암묵적 유효 검사에 너무 의존하면 실패 원자성을 해칠 수 있음
<aside> 🏷️
실패 원자성
메서드 호출이 실패하더라도 객체나 시스템이 이전 상태를 유지해야 한다는 원칙