12. toString을 항상 재정의하라
12. toString을 항상 재정의하라
🔑 핵심 내용
✔ toString은 객체를 글자로 표현하는 방법이다
✔ 좋은 toString은 디버깅과 로그 확인에 정말 도움이 된다
toString이란 무엇일까?
toString은 객체를 문자열(글자)로 바꿔주는 메서드다
모든 자바 객체는 toString 메서드를 가지고 있다
Object의 기본 toString은
클래스이름@16진수해시코드
형태로 반환한다 ➡ 예: Student@1b6d3586
🚫 기본 toString의 문제점
public class Student {
private String name;
private int grade;
public Student(String name, int grade) {
this.name = name;
this.grade = grade;
}
// toString을 재정의하지 않음
}
// 사용 예시
Student student = new Student("민수", 3);
System.out.println(student); // 출력: Student@1b6d3586
➡ 이 출력값은 "민수"가 3학년이라는 중요한 정보를 알려주지 않는다!
✅ 올바르게 toString()을 재정의한 예시
public class Student {
private String name;
private int grade;
public Student(String name, int grade) {
this.name = name;
this.grade = grade;
}
// toString 재정의
@Override
public String toString() {
return name + "(" + grade + "학년)";
}
}
// 사용 예시
Student student = new Student("민수", 3);
System.out.println(student); // 출력: 민수(3학년)
➡ 이제 출력값이 훨씬 유용해졌다!
toString이 자동으로 호출되는 경우
✔ System.out.println() 에서 객체를 출력할 때
✔ 디버깅 할 때 객체를 볼 때
✔ 문자열 연결(+) 연산에서
✔ 로그 메시지를 출력할 때
✔ assert 구문에서
toString 만들 때 고려할 점
모든 중요한 정보를 포함한다
객체가 가진 핵심 데이터를 모두 보여준다
포맷을 문서화할지 결정한다
포맷을 정해두면: 일관된 형태로 사용할 수 있다
포맷을 정하지 않으면: 나중에 마음대로 바꿀 수 있다
좋은 toString의 이점
디버깅이 쉬워진다
// 좋지 않은 toString: Found bug in: Student@1b6d3586 // 좋은 toString: Found bug in: 민수(3학년)
로그 확인이 편해진다
// 좋지 않은 toString: User Student@1b6d3586 logged in at 14:32 // 좋은 toString: User 민수(3학년) logged in at 14:32
컬렉션을 사용할 때 유용하다
Map<Student, String> attendance = new HashMap<>(); attendance.put(new Student("민수", 3), "출석"); attendance.put(new Student("영희", 3), "결석"); // 좋지 않은 toString: {Student@776ec8df=출석, Student@4eec7777=결석} // 좋은 toString: {민수(3학년)=출석, 영희(3학년)=결석} System.out.println(attendance);
좋은 toString()을 작성하는 원칙
간결하고 이해하기 쉬운 정보 제공
toString()은 사람이 읽기 쉽게 작성해야 함.
예제: 전화번호 클래스를 위한 toString()
class PhoneNumber { int areaCode, prefix, lineNumber; PhoneNumber(int areaCode, int prefix, int lineNumber) { this.areaCode = areaCode; this.prefix = prefix; this.lineNumber = lineNumber; } @Override public String toString() { return String.format("(%03d) %03d-%04d", areaCode, prefix, lineNumber); } } public class Main { public static void main(String[] args) { PhoneNumber phone = new PhoneNumber(123, 456, 7890); System.out.println(phone); // 출력: (123) 456-7890 -> 실제 전화번호처럼보이게 포맷팅 } }
객체의 중요한 정보를 포함
너무 많은 정보를 넣으면 안 됨. 핵심 정보만 포함해야 함.
포맷을 문서화할지 고민
포맷을 문서화하면 표준화되지만, 변경하기 어려워짐.
포맷을 정하지 않으면 유연성 증가 (하지만 예측하기 어려움).
toString()을 재정의하지 않으면 발생하는 문제
나쁜 예시
import java.util.HashMap;
import java.util.Map;
public class Main {
public static void main(String[] args) {
Map<Person, String> map = new HashMap<>();
map.put(new Person("Alice"), "Developer");
System.out.println(map); // 출력: {Person@6d06d69c=Developer}
}
}
➡ 사람이 읽기 어려움!
해결 방법: toString() 재정의
@Override
public String toString() {
return "이름: " + name;
} // 출력: {이름: Alice=Developer}
➡ 사람이 읽기 쉽게 개선됨
toString()을 잘못 구현했을 때의 문제
나쁜 예시
@Override
public String toString() {
return "항상 같은 값";
}
➡ 모든 객체가 같은 값을 반환해서 객체를 구분할 수 없음
좋은 예제
@Override
public String toString() {
return "이름: " + name;
}
➡ 각 객체의 정보를 정확히 표현
toString() 반환값의 포맷을 문서화할지 결정해야 한다
포맷을 명시하면 좋은 점
표준화 & 가독성 향상
toString()의 포맷을 미리 정하면 일관된 형식으로 유지 가능
사람이 읽기 쉬워지고, 디버깅이 편리해짐
데이터 저장 및 변환 가능
CSV, JSON 등으로 쉽게 변환하여 저장할 수 있음
네트워크 통신 시 문자열 기반 데이터 전송 가능
객체 ↔ 문자열 변환 가능
특정 포맷을 가진 문자열을 객체로 다시 변환 가능
정적 팩터리 메서드(fromString())를 함께 제공하면 좋음
포맷을 명시하면 생기는 문제점
유연성이 떨어짐
한 번 포맷을 정하면 변경하기 어려움
기존 시스템이 그 포맷을 따르고 있을 가능성이 높음
향후 확장성 제한
더 많은 정보를 추가하고 싶어도 기존 포맷을 유지해야 함
포맷을 문서화한 예시
/**
* 전화번호를 문자열로 표현한다.
* 형식은 "(XXX) YYY-ZZZZ" 이다.
* XXX는 지역번호, YYY는 국번, ZZZZ는 선번호다.
*/
@Override
public String toString() {
return String.format("(%03d) %03d-%04d",
areaCode, prefix, lineNum);
}
➡ 전화번호 형식이 표준화됨
포맷을 문서화하지 않은 예시
/**
* 이 학생의 정보를 담은 문자열을 반환한다.
* 정확한 형식은 정해지지 않았으며 변경될 수 있다.
*/
@Override
public String toString() {
return name + "(" + grade + "학년)";
}
➡ 포맷이 정해지지 않아 미래에 수정 가능
toString 재정의가 필요 없는 경우
✔ 정적 유틸리티 클래스 - 예: Math, Arrays 같은 정적 메서드만 있는 클래스
✔ 대부분의 열거 타입(enum) - 자바가 이미 적절한 toString을 제공하기에 굳이 재정의할 필요가 없음
🧩 어려웠던 점
toString()을 잘못 구현하면 오히려 디버깅이 더 어려워질 수 있다
포맷을 정하는 것이 유연성과 표준화 사이에서 고민해야 하는 부분이 어려웠다
💭 느낀 점
toString()은 작은 기능 같지만, 디버깅과 유지보수에서 엄청난 도움이 된다
특히, System.out.println(객체)를 사용할 때 가독성이 훨씬 좋아짐을 경험할 수 있었다
Last updated