2023. 1. 31. 14:16ใJAVA/Effective JAVA
item12. toString์ ํญ์ ์ฌ์ ์ํ๋ผ.
Object์ ๊ธฐ๋ณธ toString ๋ฉ์๋๋ ๋ณดํต 'ํด๋์ค์ด๋ฆ@16์ง์๋ก ํ์ํ ํด์์ฝ๋' ๋ก ๋ฐํํ๋ค.
์ด ๊ธฐ๋ณธ ๋ฉ์๋๋ ์ฐ๋ฆฌ๊ฐ ์ฌ์ฉํ๋ฉด์ ๊ทธ๋ฅ ์ค์ํ ์ ๋ณด๋ฅผ ๋๊ฒจ์ฃผ๋๊ฒ์ด ์๋๊ธฐ ๋๋ฌธ์ ์ฌ์ ์๋ฅผ ํ์ฌ ์ ์ตํ ์ ๋ณด๋ฅผ ๋๊ฒจ์ฃผ๋ ๊ฒ์ด ์ข๋ค.
toString ์ผ๋ฐ ๊ท์ฝ์ ๋ฐ๋ฅด๋ฉด '๊ฐ๊ฒฐํ๋ฉด์ ์ฌ๋์ด ์ฝ๊ธฐ ์ฌ์ด ํํ์ ์ ์ตํ ์ ๋ณด'๋ฅผ ๋ฐํํด์ผ ํ๋ค'๊ณ ํ๋ค.
๊ทธ๋ฆฌ๊ณ ๋ '๋ชจ๋ ํ์ ํด๋์ค์์ ์ด ๋ฉ์๋๋ฅผ ์ฌ์ ์ํ๋ผ๊ณ ํ๋ค'
toString์ ์ ๊ตฌํํ ํด๋์ค๋ ์ฌ์ฉํ๊ธฐ์๋ ํจ์ฌ ํธํ๊ณ ์ด ํด๋์ค๋ฅผ ์ฌ์ฉํ ์์คํ ์ ๋๋ฒ๊น ํ๊ธฐ ์ฌ์์ง๋ค.
toString ๋ฉ์๋๋ ๊ฐ์ฒด๋ฅผ println์ด๋ printf, ๋ฌธ์์ด ์ฐ๊ฒฐ ์ฐ์ฐ์(+), assert ๊ตฌ๋ฌธ์ ๋๊ธธ ๋ , ํน์ ๋๋ฒ๊ฑฐ๊ฐ ๊ฐ์ฒด๋ฅผ ์ถ๋ ฅํ ๋ ์๋์ผ๋ก ๋ถ๋ฆฐ๋ค. (๋๋ ์ฌ์ฉ์๊ฐ ์ง์ ํธ์ถํ์ง ์๋๋ผ๋ ๋ค๋ฅธ ๊ณณ์์ ์ฐ์ผ ์ ์๋ค.)
package chapter02.item12;
/**
* item12. toString์ ํญ์ ์ฌ์ ์ํ๋ผ.
*/
public class PhoneNumber
{
private final short areaCode, prefix, lineNum;
public PhoneNumber(int areaCode, int prefix, int lineNum)
{
this.areaCode = rangeCheck(areaCode, 999, "area code");
this.prefix = rangeCheck(prefix, 999, "prefix");
this.lineNum = rangeCheck(lineNum, 9999, "line num");
}
// toString์ด ๋ฐํ๋ ๊ฐ์ ํฌํจ๋ ์ ๋ณด๋ฅผ ์ป์ ์ ์๋ API๋ฅผ ์ ๊ณตํ๋ ๊ฒ์ด ์ข๋ค.
public short getAreaCode()
{
return areaCode;
}
public short getPrefix()
{
return prefix;
}
public short getLineNum()
{
return lineNum;
}
private static short rangeCheck(int val, int max, String arg)
{
if (val < 0 || val > max) {
throw new IllegalArgumentException(arg + ": " + val);
}
return (short) val;
}
@Override
public boolean equals(Object o)
{
if (this == o)
return true;
if (!(o instanceof PhoneNumber)) {
return false;
}
PhoneNumber that = (PhoneNumber) o;
return areaCode == that.areaCode && prefix == that.prefix && lineNum == that.lineNum;
}
@Override
public int hashCode()
{
int result = Short.hashCode(areaCode);
result = result + 31 * Short.hashCode(prefix);
result =result + 31 * Short.hashCode(lineNum);
return result;
}
/**
* ์ด ์ ํ๋ฒํธ์ ๋ฌธ์์ด ํํ์ ๋ฐํํ๋ค.
* ์ด ๋ฌธ์์ด์ "XXX-YYY-ZZZZ" ํํ์ 12๊ธ์๋ก ๊ตฌ์ฑ๋๋ค.
* XXX๋ ์ง์ญ์ฝ๋, YYY๋ ํ๋ฆฌํฝ์ค, ZZZZ๋ ๊ฐ์
์ ๋ฒํธ๋ค.
* ๊ฐ๊ฐ์ ๋๋ฌธ์๋ 10์ง์ ์ซ์ ํ๋๋ฅผ ๋ํ๋ธ๋ค.
*
* ์ ํ๋ฒํธ์ ๊ฐ ๋ถ๋ถ์ ๊ฐ์ด ๋๋ฌด ์์์ ์๋ฆฟ์๋ฅผ ์ฑ์ธ ์ ์๋ดใด,
* ์์์๋ถํฐ 0์ผ๋ก ์ฑ์๋๊ฐ๋ค.
* ์๋ก ๊ฐ์
์ ๋ฒํธ๊ฐ 123์ด๋ผ๋ฉด ์ ํ๋ฒํธ์ ๋ง์ง๋ง ๋ค ๋ฌธ์๋ "0123"์ด๋ค.
*/
@Override
public String toString()
{
return String.format("%03d-%03d-%04d", areaCode, prefix, lineNum);
}
/**
* ์ ์ ํฉํฐ๋ฆฌ๋ ์์ฑ์๋ฅผ ์ ๊ณตํ๋ ๊ฒ๋ ์ข๋ค.
* @param phoneNumberString
* @return
*/
public static PhoneNumber of(String phoneNumberString)
{
String[] split = phoneNumberString.split("-");
PhoneNumber phoneNumber = new PhoneNumber(Integer.parseInt(split[0]), Integer.parseInt(split[1]), Integer.parseInt(split[2]));
return phoneNumber;
}
}
1๏ธโฃ ์ค์ ์์ toString์ ๊ทธ ๊ฐ์ฒด๊ฐ ๊ฐ์ง ์ฃผ์ ์ ๋ณด ๋ชจ๋๋ฅผ ๋ฐํํ๋๊ฒ ์ข๋ค.
-> ํ์ง๋ง ์ดํํฐ๋ธ ์๋ฐ ๊ฐ์๋ฅผ ๋ค์ ๋ ๊ฐ์ฌ๋์ ์ค์ ์์ ๊ฐ์ฒด๊ฐ ๊ฐ์ง ์ฃผ์ ์ ๋ณด ๋ชจ๋๋ฅผ ๋ฐํํ๋๊ฑด ์ํฉ์ ๋ฐ๋ผ ๋ง์ง ์์ ์๋ ์๋ค๊ณ ํ์ จ๋ค.
์๊ฐํด๋ณด๋ฉด ๊ณ ๊ฐ ์ ๋ณด์ ๊ฐ์ด ์ด๋๊ฐ์ ๋ ธ์ถ๋์ด์๋ ์๋๋ ์ ๋ณด๊ฐ ์๋๋ฐ ์ด๋ฅผ toString์ผ๋ก ๋ณด์ฌ์ฃผ๋๊ฑด ๊ณต๊ฐ๋ฅผ ํ๋ ๊ฒ์ด๊ธฐ ๋๋ฌธ์ ์ด๋ฐ ๊ฒฝ์ฐ์๋ ๋ชจ๋ ์ฃผ์ ์ ๋ณด๋ฅผ ๋ฐํํ๋๊ฒ์ ๋ง์ง ์๋ค๊ณ ์๊ฐํ๋ค.
2๏ธโฃ ๊ฐ ํด๋์ค๋ผ๋ฉด ํฌ๋งท์ ๋ฌธ์์ ๋ช ์ํ๋ ๊ฒ์ด ์ข์ผ๋ฉฐ, ํด๋น ํฌ๋งท์ผ๋ก ๊ฐ์ฒด๋ฅผ ์์ฑํ ์ ์๋ ์ ์ ํฉํฐ๋ฆฌ๋ ์์ฑ์๋ฅผ ์ ๊ณตํ๋ ๊ฒ์ด ์ข๋ค.
/**
* ์ด ์ ํ๋ฒํธ์ ๋ฌธ์์ด ํํ์ ๋ฐํํ๋ค.
* ์ด ๋ฌธ์์ด์ "XXX-YYY-ZZZZ" ํํ์ 12๊ธ์๋ก ๊ตฌ์ฑ๋๋ค.
* XXX๋ ์ง์ญ์ฝ๋, YYY๋ ํ๋ฆฌํฝ์ค, ZZZZ๋ ๊ฐ์
์ ๋ฒํธ๋ค.
* ๊ฐ๊ฐ์ ๋๋ฌธ์๋ 10์ง์ ์ซ์ ํ๋๋ฅผ ๋ํ๋ธ๋ค.
*
* ์ ํ๋ฒํธ์ ๊ฐ ๋ถ๋ถ์ ๊ฐ์ด ๋๋ฌด ์์์ ์๋ฆฟ์๋ฅผ ์ฑ์ธ ์ ์๋ดใด,
* ์์์๋ถํฐ 0์ผ๋ก ์ฑ์๋๊ฐ๋ค.
* ์๋ก ๊ฐ์
์ ๋ฒํธ๊ฐ 123์ด๋ผ๋ฉด ์ ํ๋ฒํธ์ ๋ง์ง๋ง ๋ค ๋ฌธ์๋ "0123"์ด๋ค.
*/
@Override
public String toString()
{
return String.format("%03d-%03d-%04d", areaCode, prefix, lineNum);
}
/**
* ์ ์ ํฉํฐ๋ฆฌ๋ ์์ฑ์๋ฅผ ์ ๊ณตํ๋ ๊ฒ๋ ์ข๋ค.
* @param phoneNumberString
* @return
*/
public static PhoneNumber of(String phoneNumberString)
{
String[] split = phoneNumberString.split("-");
PhoneNumber phoneNumber = new PhoneNumber(Integer.parseInt(split[0]), Integer.parseInt(split[1]), Integer.parseInt(split[2]));
return phoneNumber;
}
-> ํฌ๋งท์ ๋ช ์ํ๊ธฐ๋ก ํ์ผ๋ฉด ๋ช ์ํ ํฌ๋งท์ ๋ง๋ ๋ฌธ์์ด๊ณผ ๊ฐ์ฒด๋ฅผ ์ํธ ์ ํํ ์ ์๋ ์ ์ ํฉํฐ๋ฆฌ๋ ์์ฑ์๋ฅผ ํจ๊ป ์ ๊ณตํด์ฃผ๋ฉด ์ข๋ค.
3๏ธโฃ toString์ด ๋ฐํํ ๊ฐ์ ํฌํจ๋ ์ ๋ณด๋ฅผ ์ป์ด์ฌ ์ ์๋ API๋ฅผ ์ ๊ณตํ๋ ๊ฒ์ด ์ข๋ค.
public short getAreaCode()
{
return areaCode;
}
public short getPrefix()
{
return prefix;
}
public short getLineNum()
{
return lineNum;
}
PhoneNumber ํด๋์ค์์๋ ์ง๊ธ ์ง์ญ์ฝ๋, ํ๋ฆฌํฝ์ค, ๊ฐ์ด์ ๋ฒํธ์ฉ ์ ๊ทผ์๋ฅผ ์ ๊ณตํด์ผ ํ๋ค.
์ ๊ทผ์๋ฅผ ์ ๊ณตํ์ง ์์ผ๋ฉด ์ฌ์ฉ์๊ฐ toString์ ๋ฐํ๊ฐ์ ํ์ฑํด์ ์ฌ์ฉํด์ผ ํ๊ณ , ๊ทธ๋ฌ๋ฉด ์ฑ๋ฅ๋ ๋๋น ์ง๊ณ ๊ตณ์ด ํ์์๋ ์์ ์ ํ๋ ๊ฒ์ด๊ธฐ ๋๋ฌธ์ด๋ค.
4๏ธโฃ ๊ฒฝ์ฐ์ ๋ฐ๋ผ AutoValue, ๋กฌ๋ณต ๋๋ IDE๋ฅผ ์ฌ์ฉํ์ง ์๋๊ฒ ์ ์ ํ ์ ์๋ค.
์ด๋ ๊ฒ toStirng ์์ฑ์ ๋์์ฃผ๋ ์๋์์ฑ ๊ธฐ๋ฅ๋ค์ด ํด๋์ค์ ์๋ฏธ๊น์ง ํ์ ํ์ง๋ ๋ชปํ๊ธฐ ๋๋ฌธ์ PhoneNumber์ฒ๋ผ ์ง์ ์ ์ํด์ฃผ๋ ๊ฒ์ด ๋ ๋์ ์๋ ์๋ค.
๐ก ๋ชจ๋ ๊ตฌ์ฒด ํด๋์ค์์ Object์ toString์ ํด๋น ๊ฐ์ฒด์ ๊ดํ ๋ช ํํ๊ณ ์ ์ฉํ ์ ๋ณด๋ฅผ ์ ๊ณตํ๋ ํํ๋ก ์ฌ์ ์ํ์!