[Effective Java] 아이템 49 : 매개변수가 유효한지 검사하라

Loopy·2022년 10월 1일
0

이펙티브 자바

목록 보기
48/76
post-thumbnail

메서드와 생성자는 입력 매개변수의 값이 특정 조건을 만족해야 하는 경우가 많은데, 이러한 경우 오류는 가능한 한 빨리 검사해야 하는 것이 좋으므로 메서드 몸체가 시작되기 전에 매개변수를 검사하는 것이 좋다.

만약 매개변수 검사를 제대로 하지 못하면, 아래와 같이 실패 원자성(아이템 74)을 어기는 문제가 발생한다.

1) 메서드가 수행되는 중간에 예외를 던지며 실패
2) 메서드는 잘 수행되지만 잘못된 결과를 반환
3) 메서드는 잘 수행되지만 객체를 이상한 상태로 만들어 놓아서 미래에 메서드와는 관련 없는 오류를 발생시킴

1️⃣ 매개변수를 검사하는 방법 : 공개 메서드

🔗 @throws

public과 protected 메서드는 매개변수 값이 잘못됐을 때 던지는 예외를 @throws 자바독 태그를 활용해 문서화해야 한다.

발생하는 예외는 보통 IllegalArgumentException, IndexOutOfBoundsException, NullPointerException 중 하나가 될 것이다(아이템 72)

/**
(현재 값 mod m)을 반환한다. 
...
@param m 계수(양수여야 한다.)
@return 현재 값 Mod m
@thorws ArithmeticException m이 0보다 작거나 같으면 발생한다.
*/
public BigInteger mod(BigInteger m){
	if (m.signum() <= 0){
    	throw new ArithmeticException("계수(m)는 양수여야 합니다. " + m);
    ...
}

🔗 null 검사시 requireNonNull

@Nullable 이나 비슷한 어노테이션을 사용하여 특정 매개변수는 null이 될 수 있다고 알려줄 수 있지만, 표준적인 방법은 아니다.

대신 자바 7에서 추가된 Objects.requireNonNull 메서드를 사용한다면 더 이상 null 검사를 수동으로 하지 않아도 된다.

▶️ 생성자에서 Null 검사 기능 활용

this.strategy = Objects.requireNonNull(strategy, "전략");  // 예외 메시지 지정

🔗 Objects 범위 검사

자바 9부터는 checkFromIndexSize(), checkFromToIndex(), checkIndex() 와 같은 메서드들이 추가되면서 Objects에 범위 검사 기능도 더해졌다.

단 예외 메시지를 지정할 수 없으며 리스트와 배열 전용으로 설계되었다. 또한 닫힌 범위(양 끝단의 값을 포함하는)는 다루지 못한다는 단점이 존재한다.

2️⃣ 매개변수를 검사하는 방법 : 비공개 메서드

🔗 assert

공개되지 않은 메서드라면, 패키지 제작자가 직접 메서드가 호출되는 상황을 통제 가능하기 때문에 오직 유효한 값만이 메서드에 넘겨지리라는 것을 보증해야 한다.

즉, public 이 아닌 메서드라면 단언문(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) 런타임에 아무런 효과도, 아무런 성능 저하도 없다.

메서드가 직접 사용하지 않으나 나중에 쓰려고 저장하는 매개변수의 유효성은 더욱 신경 써서 검사해야 한다. 생성자 매개변수의 유효성 검사는, 클래스 불변식을 어기는 객체가 만들어지지 않게 하는데 꼭 필요하다.

3️⃣ 예외

메서드 몸체 실행 전에 매개변수 유효성을 검사해야 한다는 규칙에도 예외는 존재한다. 바로, 유효성 검사 비용이 지나치게 높거나 실용적이지 않을 때, 혹은 계산 과정에서 암묵적으로 검사가 수행될 때이다.

예를 들어 후자의 경우, Collections.sort(List) 처럼 객체 리스트를 정렬하는 메서드를 생각해보면 리스트 안의 객체들은 모두 상호 비교되어 있어야 하며 비교될 수 없는 타입의 객체가 들어있다면 ClassCastException을 던진다. 하지만 암묵적 유효성 검사에 너무 의존한다면 실패 원자성(아이템 76)을 해칠 수 있으니 주의하자.

📚 핵심 정리
메서드나 생성자를 작성할 때는 매개변수들에 어떠한 제약이 있을 지 생각해야 한다. 그 제약들을 문서화하고 메서드 코드 시작 부분에서 명시적으로 검사하면, 유효성 검사가 실제 오류를 처음 걸러낼 때 효과를 볼 것이다.

profile
개인용으로 공부하는 공간입니다. 잘못된 부분은 피드백 부탁드립니다!

0개의 댓글