[이펙티브 자바] 12. toString을 항상 재정의하라

노을·2023년 1월 28일
0

이펙티브 자바

목록 보기
9/14
post-thumbnail
post-custom-banner

⭐ toString을 재정의하지 않는다면...

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);
}



⭐ toString 생성 시 주의할 점


☑️ toString에는 어떤 정보가 있어야 할까?

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를 제공하자.

어차피 toString으로 노출한 정보들은 외부에 노출되어 있으니, 각 필드를 따로 따로 조회할 수 있는 API(ex.Getter)를 만들어두자는 내용이다. 만약 만들지 않는다면, 클라이언트 입장에서 문자열을 파싱해서 써야 한다.


☑️ 참고) jpa에서 순환참조를 조심하자

jpa에서 MemberTeam이 다대일 양방향 관계일 때를 생각해보자.
이때 TeamMember 두 클래스에 모든 필드를 출력하는 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;
}

만약 MembertoString를 호출하면 TeamtoString이 호출되고 또 다시 MembertoString이 호출되어 스택오버플로우가 발생한다.

jpa의 순환참조에 대한 내용은 여러 가지가 있지만
양방향 연관관계에서 엔티티의 toString으로 인해 무한루프가 생기는 경우만 말하자면,

lombok의 @toString 을 남발하지 말고, 만약 사용한다면 exclude 조건 추가하자. @ToString(exclude = "team")
또는 직접 toString을 구현해 순환참조를 방지하자.



⭐ toString 재정의가 필요 없는 경우

  • 정적 유틸리티 클래스
  • 열거 타입 : 이미 완벽한 toString 제공 함.
post-custom-banner

0개의 댓글