■ toString 재정의 이유 및 방법
- toString을 잘 구현한 클래스는 사용하기 편하고, 그 클래스에 대해서 디버깅하기 쉽다.
- map 객체를 출력하는 경우 {Jenny=PhoneNumber@adbbd} 보다는 {Jenny=707-867-5309}라는 메시지가 나오는게 훨씬 사용성이 좋다.
- 실전에서는 toString 메서드를 재작성 할 때 그 객체가 가진 주요 정보를 모두 반환하는게 좋다
- toString을 구현할 때면 반환값의 포맷을 문서화할지 정해야한다.
- 포맷을 명시하면 그 객체는 표준적이고 명확하고 사람이 읽을 수 있게 된다.
- 포맷을 명시하기로 했으면 해당 포맷에 맞는 문장렬과 객체를 상호전환할 수 있는 정적 팩터리나 생성자를 함께 제공하면 좋다.
- 단, 포맷을 한번 명시하면 평생 그 포맷에 얽매이게 된다.
- 포맷을 명시하지 않는다면 다음 릴리즈에 포맷을 변경할 수 있는 유연성을 더 가져간다
- 포맷을 명시하든 안하든 개발자의 의도는 명확히 밝혀야 한다.
- toString이 반환한 값에 대해 포함된 정보를 얻을 수 있는 API를 제공하자
- toString에 있는 getter를 제공하지 않는다면, 클라이언트에서 toString을 파싱해서 사용할지도 모른다.
@RunWith(JUnit4.class)
public class ToStringTest {
@Test
public void toString테스트() {
String phoneNumber = "707-908-9999";
assertEquals(PhoneNumber.parse(phoneNumber), new PhoneNumber(707, 908, 9999));
}
@Test(expected = UnknownFormatConversionException.class)
public void 파싱문자열_오류_테스트() {
String phoneNumber = "707-908";
assertEquals(PhoneNumber.parse(phoneNumber), new PhoneNumber(707, 908, null));
}
@NoArgsConstructor
@AllArgsConstructor
@Builder
public static class PhoneNumber{
private Integer areaCode;
private Integer prefix;
private Integer lineNum;
private static final Pattern phoneNumberPattern = Pattern.compile("^\\d{3}-\\d{3}-\\d{4}$");
@Override
public String toString() {
return String.format("%03d-%03d-%04d", areaCode, prefix, lineNum);
}
public static PhoneNumber parse(String phoneNumber) {
if(!phoneNumberPattern.matcher(phoneNumber).find()) {
throw new UnknownFormatConversionException(phoneNumber + " cannot be parsed");
}
String[] numbers = phoneNumber.split("-");
return PhoneNumber.builder()
.areaCode(Integer.parseInt(numbers[0]))
.prefix(Integer.parseInt(numbers[1]))
.lineNum(Integer.parseInt(numbers[2]))
.build();
}
}
■ toString을 재정의 안해도 되는 경우
- 정적 Utils 클래스는 상태를 가지는 클래스가 아니기 때문에 따로 재정의하지 않아도 된다.
- enum타입 또한 이미 완벽한 toString을 제공한다.
- 대다수의 컬렉션 구현체는 추상 컬렉션 클래스의 toString 메서드를 상속하여 사용한다.
- 라이브러리를 통해 자동 생성하자
- 구글의 @Autovalue
- Lombok의 @ToString
롬복의 @ToString 사용시 양방향 연관 관계일 경우 무한 순한 참조가 발생할 수 있으므로 ToString에서 제외할 항목을 선택할 수 있다.
@ToString(exclude = "number")
'Effective Java' 카테고리의 다른 글
[Effective Java] 아이템14 Comparable을 구현할지 고려하라 (0) | 2021.02.05 |
---|---|
[Effective Java] 아이템13 clone 재정의는 주의해서 진행하라 (0) | 2021.02.01 |
[Effective Java] 아이템11 equals를 재정의하려거든 hashCode도 재정의하라 (0) | 2021.01.24 |
[Effective Java] 아이템9 try-finally 보다는 try-with-resources를 사용하라 (0) | 2021.01.24 |
[Effective Java] 아이템10 equals는 일반 규약을 지켜 재정의하라 (0) | 2021.01.22 |