toString
을 재정의하지 않으면 Object
의 기본 toString
메서드를 사용하게 된다.
Object
의 기본 toString
은
클래스이름@16진수로_표시한_해시코드
가 출력된다.
System.out.println(phoneNumber); //PhoneNumber@adbbd
하지만 보통의 개발자들이 toString
메서드에게 기대하는 것은 707-867-5309
같은 그 클래스의 필드 값일 것이다. 따라서 toString
은 모든 구체클래스에서 재정의되어야 한다.
PhoneNumber
클래스의 toString
은 다음과 같이 재정의 해주면 된다.
@Override public String toString() {
return String.format("%03d-%03d-%04d",
areaCode, prefix, lineNum);
}
74p. 실전에서 toString은 그 객체가 가진 주요 정보 모두를 반환하는 게 좋다.
이 말이 책에서 나오는데 객체의 주요정보를 외부에 노출하면 보안에 안좋기 때문에 모든 주요정보가 아닌 보여주고 싶은 필드만 출력하게 하자.
로그 정보, 주문 내역과 같은 상세한 정보를 toString으로 노출하면 안된다!
값 클래스의 경우에는 더욱 포맷 명시, 명시한 포맷에 맞는 객체 생성 코드를 작성해야 한다.
생성자로 명시한 포맷에 따라 phoneNumber
객체 만들기
private PhoneNumber(String phoneNumberString) {
String[] split = phoneNumberString.split("-");
this.areaCode = Short.parseShort(split[0]);
this.prefix = Short.parseShort(split[1]);
this.lineNum = Short.parseShort(split[2]);
}
문자열을 phoneNumber
객체로 변환하는 정적팩터리 메서드
public static PhoneNumber of(String phoneNumberString) {
String[] split = phoneNumberString.split("-");
PhoneNumber phoneNumber = new PhoneNumber(
Short.parseShort(split[0]),
Short.parseShort(split[1]),
Short.parseShort(split[2]));
return phoneNumber;
}
어차피 toString
으로 노출한 정보들은 외부에 노출되어 있으니, 각 필드를 따로 따로 조회할 수 있는 API(ex.Getter
)를 만들어두자는 내용이다. 만약 만들지 않는다면, 클라이언트 입장에서 문자열을 파싱해서 써야 한다.
jpa
에서 Member
와 Team
이 다대일 양방향 관계일 때를 생각해보자.
이때 Team
과 Member
두 클래스에 모든 필드를 출력하는 toString
을 재정의하면 어떻게 될까?
@ToString
public class Team {
@Id
@GeneratedValue
private Long id;
private String teamName;
@OneToMany(mappedBy = "user")
private Set<Member> users;
}
@ToString
public class Member {
@Id
@GeneratedValue
private Long id;
private String userName;
@ManyToOne
private Team team;
}
만약 Member
의 toString
를 호출하면 Team
의 toString
이 호출되고 또 다시 Member
의 toString
이 호출되어 스택오버플로우가 발생한다.
jpa의 순환참조에 대한 내용은 여러 가지가 있지만
양방향 연관관계에서 엔티티의 toString
으로 인해 무한루프가 생기는 경우만 말하자면,
lombok의 @toString
을 남발하지 말고, 만약 사용한다면 exclude
조건 추가하자. @ToString(exclude = "team")
또는 직접 toString
을 구현해 순환참조를 방지하자.