Effective Java : 아이템 12. toString을 항상 재정의하라.

    들어가기 전

    이 글은 인프런 백기선님의 강의를 복습하며 작성한 글입니다. 


    핵심 정리

    • toString은 간결하면서 사람이 읽기 쉬운 형태의 유익한 정보를 반환해야한다.
    • Object의 toString은 클래스이름@16진수로 표시한 해시 코드 (기본 값)
    • 객체가 가진 정보 중 공개해도 되는 정보만 표시하는 것이 좋다. 
    • 값 클래스라면 포멧을 문서에 명시하는 것이 좋으며, 해당 포멧으로 객체를 생성할 수 있는 정적 팩터리나 생성자를 제공하는 것이 좋다
    • toString이 반환한 값에 포함된 정보를 얻어올 수 있는 API를 제공하는 것이 좋다.
      • toString()은 공개된 정보이기 때문에 각각을 얻어올 수 있는 Getter 메서드를 제공해주는 것이 좋다. 
    • 경우에 따라 롬복 또는 IDE를 사용하지 않는게 적절할 수 있다. 
      • 원하는 포멧이 있을 때 사용하지 않는게 적절할 수 있음. 이 때는 직접 구현하면 됨. 

     

    toString은 객체를 print 했을 때, 대신 호출되도록 작성되어있다. 대부분 객체가 가진 정보를 보기 위해서 찍어보기 때문에 toString()은 사람이 읽기 쉬운 형티의 유익한 정보를 제공해줘야한다. Object의 toString()은 기본적으로 클래스이름@16진수를 출력해준다. 이 정보 자체는 크게 쓸모가 없다. 만약 toString()을 자주 호출해야 할 클래스라면, 적절한 정보를 제공할 수 있도록 toString() 메서드를 재정의하는 것이 좋다. 


    값 클래스라면 포멧을 문서에 명시하는 것이 좋으며, 해당 포멧으로 객체를 생성할 수 있는 정적 팩터리나 생성자를 제공하는 것이 좋다

    toString()이 제공하는 포멧을 toString() 메서드에 문서화 해두는 것이 좋다. 코드만 보았을 때는 어떤 형태로 출력될지 정확히 모르기 때문에 알려주는 것이라고 생각한다.

    또한 이 toString()을 정상적으로 노출할 수 있도록 팩토리 메서드를 제공하는 것이 좋다고 한다. 이것은 테스트 코드에서 객체를 생성해서 바로 toString()을 호출해서 어떤 패턴인지 인식하도록 하는데 도움이 될 것이기 때문이다. 

     

    /**
     * 이 전화번호의 문자열 표현을 반환한다.
     * 이 문자열은 "XXX-YYY-ZZZZ" 형태의 12글자로 구성된다.
     * XXX는 지역 코드, YYY는 프리픽스, ZZZZ는 가입자 번호다.
     * 각각의 대문자는 10진수 숫자 하나를 나타낸다.
     *
     * 전화번호의 각 부분의 값이 너무 작아서 자릿수를 채울 수 없다면,
     * 앞에서부터 0으로 채워나간다. 예컨대 가입자 번호가 123이라면
     * 전화번호의 마지막 네 문자는 "0123"이 된다.
     */
    @Override public String toString() {
        return String.format("%03d-%03d-%04d",
                areaCode, prefix, lineNum);
    }
    
    // 포멧을 호출할 수 있는 정적 팩토리 메서드 추가하기.
    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()은 public API다. 따라서 toString()을 통해서 노출되는 정보는 공개 정보이며, 공개 정보는 외부로 노출할 수 있는 정보만 선택해야한다. toString()을 통해서 이미 제공한 정보이기 때문에 각 정보에 대한 Getter를 제공하는 것도 좋은 선택이 될 수 있다.

    이미 정보는 공개되어 있는데, 각 정보를 선택적으로 가져다 쓰고 싶을 수 있기 때문에 이 때 각 정보에 대한 Getter()를 제공하는 것이다. 

    @Override 
    public String toString() {
        return String.format("%03d-%03d-%04d",
                areaCode, prefix, lineNum);
    }
    
    // 정보 제공
    public short getAreaCode() {
        return areaCode;
    }
    
    // 정보 제공
    public short getPrefix() {
        return prefix;
    }
    
    // 정보 제공
    public short getLineNum() {
        return lineNum;
    }

    경우에 따라 롬복 또는 IDE를 사용하지 않는게 적절할 수 있다.

    toString()으로 출력하고 싶은 포멧이 있는 경우라면 롬복 / IDE가 적절하지 않을 수 있다. 이 경우에는 toString()을 직접 구현해서 사용해야 한다. 아래에서 확인할 수 있듯이 인텔리제이가 제공하는 toString()은 우리가 원하는 것과는 다른 형태다.

    // 우리가 원하는 포멧
    @Override public String toString() {
        return String.format("%03d-%03d-%04d",
                areaCode, prefix, lineNum);
    }
    
    // 인텔리제이 제공
    @Override
    public String toString() {
        return "PhoneNumber{" +
                "areaCode=" + areaCode +
                ", prefix=" + prefix +
                ", lineNum=" + lineNum +
                '}';
    }

     

    댓글

    Designed by JB FACTORY