Post

Item 12 - toString을 항상 재정의하라

toString을 항상 재정의하라

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
/**  
* Returns a string representation of this collection.  The string
* representation consists of a list of the collection's elements in the
* order they are returned by its iterator, enclosed in square brackets
* ({@code "[]"}).  Adjacent elements are separated by the characters
* {@code ", "} (comma and space).  Elements are converted to strings as
* by {@link String#valueOf(Object)}.
*
* @return a string representation of this collection
*/
public String toString() {
    Iterator<E> it = iterator();
    if (! it.hasNext())
        return "[]";

    StringBuilder sb = new StringBuilder();
    sb.append('[');
    for (;;) {
        E e = it.next();
        sb.append(e == this ? "(this Collection)" : e);
        if (! it.hasNext())
            return sb.append(']').toString();
        sb.append(',').append(' ');
    }
}
  • Object의 toString은 클래스 이름@16진수로_표현한_해시코드를 반환한다.
  • toString 메서드는 객체를 println, printf, 문자열 연결 연산자(+), assert 구문에 넘길 때, 혹은 디버거가 객체를 출력할 때 자동으로 호출된다.
  • 즉, 직접 호출하지 않아도 다른 어딘가에서 쓰일 수 있다.
  • 따라서 toString이 유익한 정보를 반환할 수 있도록 하위 클래스에서 재정의하자.

toString은 그 객체가 가진 주요 정보 모두를 반환하는게 좋다.

간결하면서 사람이 읽기 쉬운 형태의 유익한 정보를 반환하자.

포맷 문서화 여부를 결정하자

toString 구현 시, 반환 값의 포맷을 문서화할 지 여부를 결정해야 한다.

전화번호나 행렬 같은 값 클래스라면 포맷을 문서에 명시하는 것이 좋다.

포맷을 명시하기로 했다면, 명시한 포맷에 맞는 문자열과 객체를 생성할 수 있는 정적 팩터리나 생성자를 제공하는 것이 좋다.

포맷을 명시한 예

1
2
3
4
5
6
7
8
9
10
/**
 * 전화번호의 문자열 표현을 반환한다.
 * 이 문자열은 "XXX-YYY-ZZZZ" 형태의 11글자로 구성된다.
 * XXX는 지역 코드, YYY는 프리픽스, ZZZZ는 가입자 번호다.
 */
@Override
public String toString() {
    return String.format("%03d-%03d-%04d",
            areaCode, prefix, lineNum);
}

포맷을 명시하지 않은 예

1
2
3
4
5
6
7
8
@Override
public String toString() {
    return "PhoneNumber{" +
                "areaCode='" + areaCode + '\'' +
                ", prefix='" + prefix + '\'' +
                ", lineNum='" + lineNum + '\'' +
                '}'; 
}

반환 값의 정보를 API로 제공하자

포맷 여부와 상관 없이 toString이 반환한 값에 포함된 정보를 얻어올 수 있는 API를 제공하자.

ex) PhoneNumber 클래스는 필요한 지역 코드, 프리픽스, 가입자 번호용 접근자를 제공해야 한다.

그렇지 않으면 프로그래머가 반환 값을 직접 파싱해야 한다.

💡 핵심 정리

  • 모든 구체 클래스에서 Object의 toString을 재정의해서 사용하자.
  • 상위 클래스에서 알맞게 재정의한 경우는 예외다.
  • 알맞게 재정의한 toString은 사용하기에도 유용하고 디버깅도 편해진다.
  • 해당 객체에 관한 명확하고 유용한 정보를 읽기 좋은 형태로 반환해야 한다.
This post is licensed under CC BY 4.0 by the author.