규칙 38 - 인자의 유효성을 검사하라
규칙 39 - 필요하다면 방어적 복사본을 만들라
규칙 40 - 메서드 시그니처는 신중하게 설계하라


아래 책를 참고하여 학습한 내용을 정리/기록한 포스트입니다. 자세한 내용은 책을 참고하시기 바라며, 문제가 있을 경우 연락 부탁드립니다.


  • 조슈아 블로크, 이병준(옮긴이), Effective Java, 2판, 인사이트, 2015.



규칙 38. 인자의 유효성을 검사하라

요약

  • 메서드나 생성자를 구현할 때 받을 수 있는 인자에 제한이 있는지 따져볼 것
  • 제한이 있다면 문서에 남기고, 메서드 앞부분에서 검사

invalid 인자가 전달되어도, 메서드 앞부분에서 인자 유효성 검사를 하면 적정한 예외를 통해 깔끔하고 신속하게 오류를 검출할수 있다. 그렇지 않으면 처리 도중에 이상한 예외를 내면서 죽거나, 제대로 실행하는 것 같은데 잘못된 결과가 나오거나, 다른 값에 영향을 주거나, 아무 상관 없는 부분에서 오류가 발생하는데 그 시간과 위치를 프로그램을 실행할 때마다 다를 수도 있다.

public 메서드라면 인자 유효성이 위반되었을 경우에 발생하는 예외를 javadoc의 @throws 태그를 사용해서 문서화하라(규칙 62).

public이 아닌 메서드는 일반적으로 인자 유효성을 검사할 때 assertion을 이용한다.

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;
... // 계산 수행
}
  • assertion은 클라이언트가 패키지를 어떻게 이용하던 확증 조건(asserted condition)은 항상 참이 되어야 한다고 주장하는 것
  • 통상적인 유효성 검사와는 달리, 확증문은 확증 조건이 만족되지 않으면 AssertionError를 발생.
  • 통상의 유효성 검사와는 달리, 활성화되지 않은 확증문은 실행되지 않으므로 비용이 0이다.
  • 확증문을 활성화시키려면 java 인터프리터에 -ea(-enableassertions) 옵션을 주어야 한다.

규칙 39. 필요하다면 방어적 복사본을 만들라

  • 만드는 클래스의 클라이언트가 불변식을 망가뜨리기 위해 최선을 다할 것이라는 가정하에, 방어적 프로그래밍해야 한다.
  • 객체 내부를 보호하려면 생성자로 전달되는 변경 가능 객체를 반드시 방어적으로 복사한다.
  • 접근자는 내부 필드에 대한 방어적 복사본을 반환하도록 한다.
  • 객체의 컴포넌트로는 가능하다면 변경 불가능 객체를 사용하라.
  • 오버헤그가 크거나, 사용자가 부적절하게 사용하지 않는다는 보장이 있을 때는, 문서에 명시하고 넘어갈 수 있다.

규칙 40. 메서드 시그니처는 신중하게 설계하라

API 설계할 때 참고하면 좋은 팁, 잘 적용하면 배우기도 쉽고 사용하기도 쉽고 오류가 날 가능성도 적은 API를 만드는데 도움이 될 것

메서드 이름은 신중하게 고르라.

  • 모든 이름은 표준 작명 관습(standard naming convention)을 따아야 한다(규칙 56).
  • 최우선 목표는 이해하기 쉬우면서도 같은 패키지 안의 다른 이름들과 일관성이 유지되는 이름으로 선택
  • 좀 더 널리 합의된 사항에도 부합하는 이름으로 고를 것, 자바 라이브러리 확인

편의 메서드(convenience method)를 제공하는데 너무 열 올리지 마라.

  • 모든 메서드는 “맡은 일이 명확하고 거기 충실해야(pull its weight)” 한다.
  • 클래스에 너무 메서드가 많으면 학습, 사용, 테스트, 유지보수 등의 모든 측면에서 어렵다.
  • 인터페이스의 경우에는 메서드가 많으면 문제가 두 배는 더 심각하다(구현하는 사람에게도 그렇고, 사용자에게도 그렇다).
  • 수행해야 하는 동작 각각에 대해서 기능적으로 완전한 메서드를 제공하라.
  • “단축(shorthand)” 메서드는 자주 쓰일 때문 추가하라. 그럴지 잘 모르겠다면, 빼버려라.

인자 리스트(parameter list)를 길게 만들지 마라.

  • 4개 이하가 되도록 애쓰라.
  • 자료형이 같은 인자들이 길게 연결된 인자 리스트는 특히 더 위험하다.

긴 인자 리스트를 짧게 줄이는 방법

  1. 여러 메서드로 나누는 것
    • 여러 메서드가 생길수 있지만, 직교성(orthogonality) 향상을 통해 줄일 수 있다.
  2. helper class를 만들어 인자들을 그룹별로 나누는 것
    • 보통 이 helper class들은 static 맴버 클래스다(규칙 22).
    • 이 기법은 자주 등장하는 일련의 인자들이 어떤 별도 개체(entity)를 나타낼 때 쓰면 좋다.
      • 카드의 rank와 suit를 인자로 받는 메서드가 있다면, 카드를 나타내는 helper class를 만들어서 인자로 사용
  3. builder pattern을 고쳐서 객체 생성 대신 메서드 호출에 적용하는 것
    • 많은 인자가 필요하지만 그 인자들 가운데 상당수는 옵션이라면, 모든 인자를 표현하는 객체 하나를 정의하고 그 객체의 setter 메서드를 클라이언트가 여러 번 호출할 수 있도록 하면 좋다.
    • 인자가 설정되고 나면 클라이언트를 “execute” 메서드를 호출하여 최종적인 유효성 검사를 실행한 뒤 실제 계산 진행

인자의 자료형으로는 클래스보다 인터페이스가 좋다.

  • 인자를 정의하기에 적합한 인터페이스가 있다면, 구현 클래스 대신 인터페이스를 인자 자료형으로 쓰자.

인자 자료형으로 boolean을 쓰는 것보다, 원소가 2개인 enum 자료형을 쓰는 것이 낫다.

  • 좀 더 읽기 편한 코드가 만들어진다.