Object의 기본 toString 메서드는 단순히 클래스_이름@16진수로_표현한_해시코드
를 반환한다. 이는 우리가 원하는 적합한 문자열을 반환하는 형태가 아니다.
toString의 일반 규약에 따라 모든 하위 클래스에서 toString을 재정의 하여 **** 간결하면서 사람이 읽기 쉬운 형태의 유익한 정보를 반환해야 한다.
toString을 직접 호출하지 않더라도 객체를 println
, printf
, 문자열 연결 연산자 (+), assert
구문에 넘길 때 등 다양한 상황에서 사용될 수 있다.
toString을 잘 구현한 클래스는 사용하기에 훨씬 즐겁고, 그 클래스를 사용한 시스템은 디버깅하기 쉽다.
ex. Collection
public abstract class AbstractCollection<E> implements Collection<E> {
/**
* 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(' ');
}
}
}
반환값의 포맷을 문서화할지 정해야 한다. 포맷을 명시하면 그 객체는 표준적이고, 명확하고, 사람이 읽을 수 있게 된다.
포맷을 명시하기로 했다면, 명시한 포맷에 맞는 문자열과 객체를 상호 전환할 수 있는 정적 팩터리나 생성자를 함께 제공해주면 좋다. 자바 플랫폼의 많은 값 클래스가 따르는 방식이기도 하며, BigInteger
, BigDecimal
과 대부분의 기본 타입 클래스가 여기에 해당한다.
하지만 단점 또한 존재한다. 포맷을 한번 명시하면 (그 클래스가 많이 쓰인다면) 평생 그 포맷에 얽매이게 된다. 만약 향후 릴리스에서 포맷을 변경하게 되면 이를 사용하던 코드들과 데이터들은 엉망이 될 것이다.
포맷을 명시하든 아니든 의도는 분명하게 밝혀야 한다.
포맷 명시 여부와 상관없이 toString이 반환한 값에 포함된 정보를 얻어올 수 있는 API를 제공하자