본문 바로가기

reviews/Effective JAVA

012. toString을 항상 재정의하라

toString의 규약 : 모든 하위 클래스에서 이 메서드를 재정의하라.

Object의 기본 toString 메서드는 단순히 클래스_이름@16인지루_표시한_해시코드를 반환한다.

규약에 따라 잘 구현한 클래스를 사용한 시스템은 디버깅하기 쉽다.

♦︎ toString을 제공할 이유가 없는 경우

  • 정적 유틸리티 클래스
  • 대부분의 열거 타입 : 자바가 이미 완벽한 toString을 제공한다.

예외

  • 하위 클래스들이 공유해야 할 문자열 표현이 있는 추상 클래스 : 대다수의 컬렉션 구현체는 추상 컬렉션 클래스들의 toString 메서드를 상속해 쓴다.

👉 toString의 재정의 규약과 좋은 형태

  • 간결하면서 사람이 읽기 쉬운 형태의 유익한 정보를 반환한다.
  • 그 객체가 가진 주요 정보를 모두 반환하여 스스로를 완벽히 설명하는 문자열로 만든다.
  • 객체의 상태가 문자열로 표현하기 적합하지 않으면 요약 정보를 담도록 한다.

👉 반환값의 포맷을 명시하거나 문서화할 지에 대한 선택

포맷을 명시하든 아니든 의도는 명확하게 밝여야 한다.

포맷을 명시할 지는 선택이나 명시하는 경우 포맷을 개선할 수 있는 유연성을 잃게 된다.

다만, 전화번호나 행렬 같은 값 클래스라면 문서화하기를 권한다.

포맷을 명시하기로 했다면, 명시한 포맷에 맞는 문자열과 객체를 상호 전환할 수 있는 정적 팩터리나 생성자를 함께 제공해주면 좋다. (BigInteger, BigDecimal)

/** java.math.BigDecimal.java */
Returns the string representation of this BigDecimal, using scientific notation if an exponent is needed.
A standard canonical string form of the BigDecimal is created as though by the following steps: first, the absolute value of the unscaled value of the BigDecimal is converted to a string in base ten using the characters '0' through '9' with no leading zeros (except if its value is zero, in which case a single '0' character is used).
Next, an adjusted exponent is calculated; this is the negated scale, plus the number of characters in the converted unscaled value, less one. That is, -scale+(ulength-1), where ulength is the length of the absolute value of the unscaled value in decimal digits (its precision).
If the scale is greater than or equal to zero and the adjusted exponent is greater than or equal to -6, the number will be converted to a character form without using exponential notation. In this case, if the scale is zero then no decimal point is added and if the scale is positive a decimal point will be inserted with the scale specifying the number of characters to the right of the decimal point. '0' characters are added to the left of the converted unscaled value as necessary. If no character precedes the decimal point after this insertion then a conventional '0' character is prefixed.
Otherwise (that is, if the scale is negative, or the adjusted exponent is less than -6), the number will be converted to a character form using exponential notation. In this case, if the converted BigInteger has more than one digit a decimal point is inserted after the first digit. An exponent in character form is then suffixed to the converted unscaled value (perhaps with inserted decimal point); this comprises the letter 'E' followed immediately by the adjusted exponent converted to a character form. The latter is in base ten, using the characters '0' through '9' with no leading zeros, and is always prefixed by a sign character '-' ('\\u002D') if the adjusted exponent is negative, '+' ('\\u002B') otherwise).
Finally, the entire string is prefixed by a minus sign character '-' ('\\u002D') if the unscaled value is less than zero. No sign character is prefixed if the unscaled value is zero or positive.
Examples:
For each representation [unscaled value, scale] on the left, the resulting string is shown on the right.
       [123,0]      "123"
       [-123,0]     "-123"
       [123,-1]     "1.23E+3"
       [123,-3]     "1.23E+5"
       [123,1]      "12.3"
       [123,5]      "0.00123"
       [123,10]     "1.23E-8"
       [-123,12]    "-1.23E-10"
       
Notes:
There is a one-to-one mapping between the distinguishable BigDecimal values and the result of this conversion. That is, every distinguishable BigDecimal value (unscaled value and scale) has a unique string representation as a result of using toString. If that string representation is converted back to a BigDecimal using the BigDecimal(String) constructor, then the original value will be recovered.
The string produced for a given number is always the same; it is not affected by locale. This means that it can be used as a canonical string representation for exchanging decimal data, or as a key for a Hashtable, etc. Locale-sensitive number formatting and parsing is handled by the java.text.NumberFormat class and its subclasses.
The toEngineeringString method may be used for presenting numbers with exponents in engineering notation, and the setScale method may be used for rounding a BigDecimal so it has a known number of digits after the decimal point.
The digit-to-character mapping provided by Character.forDigit is used.
Returns:
string representation of this BigDecimal.
See Also:
Character.forDigit, BigDecimal(String)

# 생성자
public BigDecimal(String val) {
        this(val.toCharArray(), 0, val.length());
    }

특히 포맷을 명시하는 경우 클라이언트가 toString을 사용하여 파싱하거나, 새로운 객체를 만들거나, 영속 데이터로 저장하는 코드를 작성할 수도 있음을 유의해야 한다.

→ toString 반환 값에 포함된 정보를 얻을 수 있는 별도의 API를 제공하자.

제공하지 않을 경우 toString을 파싱해서 쓰게 되어 성능이 나빠지고 포맷 변경 시 시스템에 문제가 생길 수 있다.

AutoValue 프레임워크(혹은 일부 IDE)를 사용하면 toString을 생성해준다. ^^

반응형