[์ดํŽ™ํ‹ฐ๋ธŒ ์ž๋ฐ”] Item12. toString์„ ํ•ญ์ƒ ์žฌ์ •์˜ํ•˜๋ผ.

2023. 1. 31. 14:16ใ†JAVA/Effective JAVA

728x90

 

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์„ ํ•ด๋‹น ๊ฐ์ฒด์— ๊ด€ํ•œ ๋ช…ํ™•ํ•˜๊ณ  ์œ ์šฉํ•œ ์ •๋ณด๋ฅผ ์ œ๊ณตํ•˜๋Š” ํ˜•ํƒœ๋กœ ์žฌ์ •์˜ํ•˜์ž! 

 

 

 

 

 

 

 

 

 

728x90