들어가며
메소드와 생성자 대부분은 입력 매개변수의 값이 특정 조건을 만족하기를 바란다. 예를 들어 인덱스는 음수가 되선 안되며 객체 참조는 null이 아니여야 한다는 식이다. 이런 제약은 반드시 메소드 몸체가 시작되기 전에 검사해야한다. 이를 수행하지 않는다면 다음과 같은 문제가 생긴다.
- 메소드가 수행되는 중간에 모호한 예외를 던지며 실패한다.
- 잘못된 결과를 반환한다.
- 문제 없이 수행되었지만 어떤 객체를 이상한 상태로 만들어 놓아 미래에 알수없는 시점에 원인 메소드와 관계 없는 오류를 낸다.
자바7 부터 추가된 java.util.Objects.requireNonNull
메소드는 유연하고 사용하기도 편하며 더 이상 null 검사를 수동으로 하지 않아도 된다. 자바9 부터는 Ojbects에 범위 검사 기능도 더해졌다. checkFromIndexSize, checkFromToIndex, checkIndex가 이에 해당된다.
public이 아닌 메소드라면 assert를 사용해 매개변수 유효성을 검증할 수 있다. 즉, 유효한 값이 메소드에 넘겨지리라는 것을 보증하는 메소드라는 의미다. assert는 일반적인 유효성 검사와 다르다.
- 실패시 AssertionError를 던진다.
- 런타임에 아무런 효과도, 성능저하도 없다. 단, -ea 플레그 설정시 영향을 준다.
메소드가 직접 사용하지는 않으나 나중에 쓰기 위해 저장하는 매개변수는 특히 더 신경써서 검사해야 한다. 앞선 유효성 검사를 진행하지 않았을 때 생기는 문제의 3번에 해당한다. 생성자는 나중에 쓰려고 저장하는 매개변수의 유효성을 검사하라는 원칙의 특수한 사례다. 예를 들어 콜렉션을 랩핑하는 클래스의 생성자 매개변수에서 콜랙션을 받는데 해당 콜렉션이 null인 경우이다.
메소드 몸체 실행 전에 매개변수 유효성을 검사해야 한다는 규칙에도 예외는 있다. 유효성 검사 비용이 지나치게 높거나 실용적이지 않을 때, 혹은 계산 과정에서 암묵적으로 검사가 수행될 때다. 하지만 암묵적 유효성 검사에 너무 의존했다가는 실패 원자성을 해칠 수 있으니 주의해야 한다.
이 내용은 매개변수에 제약을 두는게 좋다라는 의미가 아니다. 그 반대이다. 메소드는 최대한 범용적으로 설계해야 한다.하지만 구현하려는 개념 자체가 특정한 제약을 내재한 경우 이를 검사하라는 의미이다.