ITEM 6: Avoid Unnecessary Object

๋˜‘๊ฐ™์€ ๊ธฐ๋Šฅ์˜ ๊ฐ์ฒด๋ฅผ ๋งค๋ฒˆ ์ƒ์„ฑํ•˜๋Š” ๊ฒƒ๋ณด๋‹ค ๊ฐ์ฒด ํ•˜๋‚˜๋ฅผ ์ƒ์„ฑํ•˜์—ฌ ์žฌ์‚ฌ์šฉํ•˜๋Š” ํŽธ์ด ์ข‹์„ ๋•Œ๊ฐ€ ๋งŽ๋‹ค. ํŠนํžˆ ๋ถˆ๋ณ€ ๊ฐ์ฒด(item 17)๋Š” ์–ธ์ œ๋“ ์ง€ ์žฌ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.

// ์•ˆ์ข‹์€ ์˜ˆ - ํ˜ธ์ถœ๋  ๋•Œ๋งˆ๋‹ค ์ธ์Šคํ„ด์Šค ์ƒˆ๋กœ ์ƒ์„ฑ
String s = new String("bad example");

์œ„์˜ ๋ฌธ์žฅ์€ ์‹คํ–‰๋  ๋•Œ๋งˆ๋‹ค String ์ธ์Šคํ„ด์Šค๋ฅผ ์ƒˆ๋กœ ๋งŒ๋“ค๋ฉฐ, ์ด ๋ฌธ์žฅ์ด ๋ฐ˜๋ณต๋ฌธ์ด๋‚˜ ๋นˆ๋ฒˆํžˆ ํ˜ธ์ถœ๋˜๋Š” ๋ฉ”์„œ๋“œ ์•ˆ์— ์žˆ๋‹ค๋ฉด, String ์ธ์Šคํ„ด์Šค๊ฐ€ ์ˆ˜์—†์ด ๋งŽ์ด ๋งŒ๋“ค์–ด ์งˆ ์ˆ˜ ์žˆ๋‹ค.

// ํ•˜๋‚˜์˜ String ์ธ์Šคํ„ด์Šค ์‚ฌ์šฉ
String s = "good example";

์œ„์˜ ๊ฒฝ์šฐ ์ƒˆ๋กœ์šด ์ธ์Šคํ„ด์Šค๋ฅผ ๋งค๋ฒˆ ๋งŒ๋“œ๋Š” ๋Œ€์‹  ํ•˜๋‚˜์˜ ์ธ์Šคํ„ด์Šค๋ฅผ ์‚ฌ์šฉํ•˜๋ฉฐ, ๊ฐ™์€ ๊ฐ€์ƒ ๋จธ์‹  ์•ˆ์—์„œ ๋˜‘๊ฐ™์€ ๋ฌธ์ž์—ด ๋ฆดํ„ฐ๋Ÿด์„ ์‚ฌ์šฉํ•˜๋Š” ๊ฒฝ์šฐ ๋ชจ๋“  ์ฝ”๋“œ๊ฐ€ ๊ฐ™์€ ๊ฐ์ฒด๋ฅผ ์žฌ์‚ฌ์šฉํ•จ์ด ๋ณด์žฅ๋œ๋‹ค.

์ •์  ํŒฉํ„ฐ๋ฆฌ ๋ฉ”์„œ๋“œ-item1๋ฅผ ์ œ๊ณตํ•˜๋Š” ๋ถˆ๋ณ€ ํด๋ž˜์Šค์—์„œ๋Š” ๋ถˆํ•„์š”ํ•œ ๊ฐ์ฒด ์ƒ์„ฑ์„ ํ”ผํ•  ์ˆ˜ ์žˆ๋‹ค.

// ์ƒ์„ฑ์ž - Java9์—์„œ deprecated
public Boolean(String s) {
  this(parseBoolean(s));
}
// ํŒฉํ„ฐ๋ฆฌ ๋ฉ”์„œ๋“œ
public static Boolean valueOf(String s) {
  return parseBoolean(s) ? TRUE : FALSE;
}

์ƒ์„ฑ์ž๋Š” ๋งค๋ฒˆ ์ƒˆ๋กœ์šด ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ•˜์ง€๋งŒ, ํŒฉํ„ฐ๋ฆฌ ๋ฉ”์„œ๋“œ๋Š” ๊ทธ๋ ‡์ง€ ์•Š์œผ๋ฏ€๋กœ, Boolean(String) ์ƒ์„ฑ์ž ๋Œ€์‹  Boolean.valuesOf(String) ํŒฉํ„ฐ๋ฆฌ ๋ฉ”์„œ๋“œ๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ด ์ข‹๋‹ค.

static boolean isRomanNumeral(String s){
  return s.matches("^(?=.)M*(C[MD]|D?C{0,3})" + "(X[CL]|L?X{0,3})(I[XV]|V?I{0,3})$");
}

์ •๊ทœ ํ‘œํ˜„์‹์„ ํ™œ์šฉํ•ด ์œ ํšจํ•œ ๋กœ๋งˆ ์ˆซ์ž์ธ์ง€ ํ™•์ธํ•˜๋Š” ๋ฉ”์„œ๋“œ์ด๋‹ค. ํ•˜์ง€๋งŒ ์ด ๋ฐฉ์‹์€ String.matches ๋ฉ”์„œ๋“œ๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค๋Š” ๋ฌธ์ œ์ ์ด ์žˆ๋‹ค.

/**
     * Tells whether or not this string matches the given <a
     * href="../util/regex/Pattern.html#sum">regular expression</a>.
     *
     * <p> An invocation of this method of the form
     * <i>str</i>{@code .matches(}<i>regex</i>{@code )} yields exactly the
     * same result as the expression
     *
     * <blockquote>
     * {@link java.util.regex.Pattern}.{@link java.util.regex.Pattern#matches(String,CharSequence)
     * matches(<i>regex</i>, <i>str</i>)}
     * </blockquote>
     *
     * @param   regex
     *          the regular expression to which this string is to be matched
     *
     * @return  {@code true} if, and only if, this string matches the
     *          given regular expression
     *
     * @throws  PatternSyntaxException
     *          if the regular expression's syntax is invalid
     *
     * @see java.util.regex.Pattern
     *
     * @since 1.4
     * @spec JSR-51
     */
    public boolean matches(String regex) {
        return Pattern.matches(regex, this);
    }

String.matches ๋ฉ”์„œ๋“œ ๋‚ด๋ถ€์—์„œ ๋งŒ๋“œ๋Š” ์ •๊ทœํ‘œํ˜„์‹์šฉ Pattern ์ธ์Šคํ„ด์Šค๋Š” ํ•œ ๋ฒˆ ์“ฐ๊ณ  ๋ฒ„๋ ค์ ธ ๊ณง ๋ฐ”๋กœ ๊ฐ€๋น„์ง€ ์ปฌ๋ ‰์…˜ ๋Œ€์ƒ์ด ๋œ๋‹ค. Pattern ์€ ์ž…๋ ฅ๋ฐ›์€ ์ •๊ทœํ‘œํ˜„์‹์— ํ•ด๋‹นํ•˜๋Š” ์œ ํ•œ ์ƒํƒœ ๋จธ์‹ (finite state machine)์„ ๋งŒ๋“ค์–ด ์ธ์Šคํ„ด์Šค ์ƒ์„ฑ ๋น„์šฉ์ด ๋†’๋‹ค.

finite state machine ์ด๋ž€

์ƒํƒœ๋ฅผ ๊ธฐ๋ฐ˜์œผ๋กœ ๋™์ž‘ํ•˜๋Š” ๊ฐœ๋…์˜ ๋ฐฉ์‹์œผ๋กœ, ์ƒํƒœ๋ฅผ ๊ธฐ๋ฐ˜์œผ๋กœ ์ฒ˜๋ฆฌ๋˜๊ธฐ ๋•Œ๋ฌธ์— ํ•œ ๋ฒˆ์— ํ•œ ๊ฐœ์˜ ์ƒํƒœ๋งŒ ์ฒ˜๋ฆฌ๋œ๋‹ค. ์ƒํƒœ์— ๊ธฐ๋ฐ˜ํ•œ ์กฐ๊ฑด์— ์˜ํ•ด ์ฒ˜๋ฆฌ๋˜๋ฏ€๋กœ, ์ƒํƒœ ๊ฐ’์ด ๋ณ€๊ฒฝ๋˜๋ฉด ์ƒํƒœ์— ๋Œ€ํ•œ ์ข…๋ฃŒ ๋ฐ ๋‹ค๋ฅธ ์ƒํƒœ๋กœ์˜ ๋ณ€ํ™˜์„ ์ฒ˜๋ฆฌํ•œ๋‹ค.

https://drehzr.tistory.com/70

์ด๋ ‡๊ฒŒ ์ƒ์„ฑ ๋น„์šฉ์ด ๋งŽ์ด ๋“œ๋Š” ๊ฐ์ฒด๊ฐ€ ๋ฐ˜๋ณตํ•ด์„œ ํ•„์š”ํ•˜๋‹ค๋ฉด, ์บ์‹ฑํ•˜์—ฌ ์žฌ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์„ ๊ถŒ์žฅํ•œ๋‹ค.

public class RomanNumerals{

  private static final Pattern ROMAN = Pattern.compile("^(?=.)M*(C[MD]|D?C{0,3})" + "(X[CL]|L?X{0,3})(I[XV]|V?I{0,3})$");

  static boolean isRomanNumeral(String s) {
    return ROMAN.matcher(s).matches();
  }
}

๋ถˆ๋ณ€์ธ Pattern ์ธ์Šคํ„ด์Šค๋ฅผ ํด๋ž˜์Šค ์ดˆ๊ธฐํ™” ๊ณผ์ •์—์„œ ์ง์ ‘ ์ƒ์„ฑํ•ด ์บ์‹ฑํ•ด๋‘๊ณ , ๋‚˜์ค‘์— isRomanNumeral ๋ฉ”์„œ๋“œ ํ˜ธ์ถœ์„ ํ†ตํ•ด ์ด ์ธ์Šคํ„ด์Šค๋ฅผ ์žฌ์‚ฌ์šฉํ•˜์—ฌ ์„ฑ๋Šฅ์„ ๊ฐœ์„ ํ•  ์ˆ˜ ์žˆ๋‹ค.

ํ•˜์ง€๋งŒ, ํด๋ž˜์Šค๊ฐ€ ์ดˆ๊ธฐํ™”๋œ ํ›„ ์ด ๋ฉ”์„œ๋“œ๋ฅผ ํ•œ ๋ฒˆ๋„ ํ˜ธ์ถœํ•˜์ง€ ์•Š๋Š”๋‹ค๋ฉด, ROMAN ํ•„๋“œ๋Š” ํ•„์š”์—†์ด ์ดˆ๊ธฐํ™” ๋œ ๊ฒƒ์ด๋‹ค. lazy initialization(item 83) ์œผ๋กœ isRomanNumeral ๋ฉ”์„œ๋“œ๊ฐ€ ์ฒ˜์Œ์œผ๋กœ ํ˜ธ์ถœ๋  ๋•Œ ํ•„๋“œ๋ฅผ ์ดˆ๊ธฐํ™”ํ•˜๋„๋ก ํ•˜์—ฌ ๋ถˆํ•„์š”ํ•œ ์ดˆ๊ธฐํ™”๋ฅผ ์—†์•จ ์ˆ˜ ์žˆ์ง€๋งŒ, ์ง€์—ฐ ์ดˆ๊ธฐํ™”๋Š” ์ฝ”๋“œ๋ฅผ ๋ณต์žกํ•˜๊ฒŒ ๋งŒ๋“œ๋Š”๋ฐ, ์„ฑ๋Šฅ์€ ํฌ๊ฒŒ ๊ฐœ์„ ๋˜์ง€ ์•Š์„ ๋•Œ๊ฐ€ ๋งŽ์œผ๋ฏ€๋กœ ๊ถŒํ•˜์ง€ ์•Š๋Š”๋‹ค.(item 67)

Map ์ธํ„ฐํŽ˜์ด์Šค์˜ KeySet ๋ฉ”์„œ๋“œ๋Š” Map ๊ฐ์ฒด ์•ˆ์˜ ๋ชจ๋“  ํ‚ค ๊ฐ’์„ ๋‹ด์€ Set ๋ทฐ๋ฅผ ๋ฐ˜ํ™˜ํ•œ๋‹ค. KeySet ํ˜ธ์ถœ์‹œ ์ƒˆ๋กœ์šด Set ์ธ์Šคํ„ด์Šค๊ฐ€ ๋งŒ๋“ค์–ด์ง„๋‹ค๊ณ  ์ƒ๊ฐํ•  ์ˆ˜ ์žˆ์ง€๋งŒ, ์‚ฌ์‹ค์€ ๋งค๋ฒˆ ๋™์ผํ•œ Set ์ธ์Šคํ„ด์Šค๋ฅผ ๋ฐ˜ํ™˜ํ•  ์ˆ˜๋„ ์žˆ๋‹ค. ๋ฐ˜ํ™˜๋œ Set ์ธ์Šคํ„ด์Šค๊ฐ€ ์ผ๋ฐ˜์ ์œผ๋กœ ๊ฐ€๋ณ€์ด๋”๋ผ๋„ ๋ฐ˜ํ™˜๋œ ์ธ์Šคํ„ด์Šค๋“ค์€ ๊ธฐ๋Šฅ์ ์œผ๋กœ ๋ชจ๋‘ ๋™์ผํ•˜๋ฉฐ, ๋ฐ˜ํ™˜๋œ ๊ฐ์ฒด ์ค‘ ํ•˜๋‚˜๋ฅผ ์ˆ˜์ •ํ•˜๋ฉด ๋ชจ๋“  ๊ฐ์ฒด๊ฐ€ ๋™์ผํ•œ Map ์„ ๋Œ€๋ณ€ํ•˜๊ธฐ ๋•Œ๋ฌธ์— ๋ชจ๋“  ๊ฐ์ฒด๊ฐ€ ๋”ฐ๋ผ์„œ ๋ฐ”๋€๋‹ค. KeySet ๋ทฐ ๊ฐ์ฒด๋ฅผ ์—ฌ๋Ÿฌ ๊ฐœ ์ƒ์„ฑํ•ด๋„ ๋˜์ง€๋งŒ, ๊ทธ๋Ÿด ํ•„์š”๋Š” ์—†๋‹ค.

๋˜ ๋‹ค๋ฅธ ์˜ˆ๋กœ auto boxing์„ ๋“ค ์ˆ˜ ์žˆ๋‹ค. auto boxing์€ ๊ธฐ๋ณธ ํƒ€์ž…๊ณผ ๋ฐ•์‹ฑ๋œ ๊ธฐ๋ณธ ํƒ€์ž…์„ ์„ž์–ด ์“ธ ๋•Œ ์ž๋™์œผ๋กœ ์ƒํ˜ธ ๋ณ€ํ™˜ํ•ด์ฃผ๋Š” ๊ธฐ์ˆ ์ด๋‹ค. ์˜คํ†ต ๋ฐ•์‹ฑ์€ ๊ธฐ๋ณธ ํƒ€์ž…๊ณผ ๊ทธ์— ๋Œ€์‘ํ•˜๋Š” ๋ฐ•์‹ฑ๋œ ๊ธฐ๋ณธ ํƒ€์ž…์˜ ๊ตฌ๋ถ„์„ ํ๋ ค์ฃผ์ง€๋งŒ, ์™„์ „ํžˆ ์—†์• ์ฃผ๋Š” ๊ฒƒ์€ ์•„๋‹ˆ๋‹ค.

private static long sum(){
  Long sum = 0L;

  for (long i = 0; i< Integer.MAX_VALUE; i++) {
    sum += i;
  }

  return sum;
}

์œ„ ์ฝ”๋“œ๋Š” ๋ชจ๋“  ์ •์ˆ˜์˜ ์ด ํ•ฉ์„ ๊ตฌํ•˜๋Š” ๋ฉ”์„œ๋“œ๋กœ, int๋ฅผ ์‚ฌ์šฉํ•˜์ง€ ์•Š๊ณ  long์„ ์‚ฌ์šฉํ•˜๊ณ  ์žˆ๋‹ค. ์ •ํ™•ํ•œ ๋‹ต์„ ๋‚ผ ์ˆ˜๋Š” ์žˆ์ง€๋งŒ, ์ œ๋Œ€๋กœ ๊ตฌํ˜„ํ•˜์˜€์„ ๋•Œ๋ณด๋‹ค ์„ฑ๋Šฅ์ƒ์œผ๋กœ ํ›จ์”ฌ ๋Š๋ ค์ง„๋‹ค. sum ๋ณ€์ˆ˜๋ฅผ long์ด ์•„๋‹Œ Long ์œผ๋กœ ์„ ์–ธํ•˜์—ฌ ๋ถˆํ•„์š”ํ•œ ์ธ์Šคํ„ด์Šค๊ฐ€ sum += i ์—ฐ์‚ฐ์ด ์ด๋ฃจ์–ด์งˆ ๋•Œ๋งˆ๋‹ค ์ƒ์„ฑ๋˜๋Š” ๊ฒƒ์ด๋‹ค. ๋‹จ์ˆœํžˆ sum์˜ ํƒ€์ž…์„ long์œผ๋กœ๋งŒ ๋ณ€๊ฒฝํ•ด์ฃผ์–ด๋„ ์„ฑ๋Šฅ์ด ๊ฐœ์„ ๋œ๋‹ค. ์ฆ‰, ๋ฐ•์‹ฑ๋œ ๊ธฐ๋ณธ ํƒ€์ž…๋ณด๋‹ค๋Š” ๊ธฐ๋ณธ ํƒ€์ž…์„ ์‚ฌ์šฉํ•˜๊ณ , ์˜๋„์น˜ ์•Š์€ ์˜คํ† ๋ฐ•์‹ฑ์ด ์ˆจ์–ด๋“ค์ง€ ์•Š๋„๋ก ์ฃผ์˜ํ•ด์•ผ ํ•œ๋‹ค.

์‹ค์ œ๋กœ ์ƒํ’ˆ์˜ ๊ฐ€๊ฒฉ์„ ๊ณ„์‚ฐํ•  ๋•Œ ์˜๋„์น˜ ์•Š์€ auto boxing์ด ํ”ํžˆ ๋ฐœ์ƒํ•œ๋‹ค. ๊ฐ€๊ฒฉ ํ•„๋“œ์— ๋Œ€ํ•œ ํƒ€์ž…์œผ๋กœ BigDecimal ์„ ์ฃผ๋กœ ์‚ฌ์šฉํ•˜๋Š”๋ฐ BigDecimal ๋‚ด๋ถ€ ๋ฉ”์†Œ๋“œ๋Š” ๊ธฐ๋ณธํƒ€์ž…์„ ์‚ฌ์šฉํ•˜๊ณ  ์žˆ๋‹ค.

public BigDecimal(long val) {
    this.intCompact = val;
    this.intVal = (val == INFLATED) ? INFLATED_BIGINT : null;
    this.scale = 0;
}
public long longValue(){
    return (intCompact != INFLATED && scale == 0) ? intCompact : toBigInteger().longValue();
}

์ด๋•Œ BigDecimal.longValue()๋กœ ์—ฐ์‚ฐ์„ ํ•˜๊ณ  ์‹ถ๋‹ค๋ฉด, ๊ธฐ๋ณธ ํƒ€์ž…์„ ์‚ฌ์šฉํ•ด์•ผํ•˜๋ฉฐ, ๊ทธ๋ ‡์ง€ ์•Š๋‹ค๋ฉด ๋ถˆํ•„์š”ํ•œ ์ธ์Šคํ„ด์Šค๊ฐ€ ์ƒ์„ฑ๋  ๊ฒƒ์ด๋‹ค.

ํ”„๋กœ๊ทธ๋žจ์˜ ๋ช…ํ™•์„ฑ, ๊ฐ„๊ฒฐ์„ฑ, ๊ธฐ๋Šฅ์„ ์œ„ํ•ด ๊ฐ์ฒด๋ฅผ ์ถ”๊ฐ€๋กœ ์ƒ์„ฑํ•˜๋Š” ๊ฒƒ์ด๋ผ๋ฉด ์ผ๋ฐ˜์ ์œผ๋กœ ์ข‹์€ ์ผ์ด๋‹ค. ๋ถˆํ•„์š”ํ•œ ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ•˜๋Š” ๊ฒƒ์„ ํ”ผํ•˜๊ณ ์ž ๊ฐ์ฒด ํ’€(pool)์„ ์ƒ์„ฑํ•˜๋Š” ๊ฒƒ์€ ๊ถŒ์žฅํ•˜์ง€ ์•Š๋Š”๋‹ค. ์ž์ฒด ๊ฐ์ฒด ํ’€์€ ์ฝ”๋“œ๋ฅผ ํ—ท๊ฐˆ๋ฆฌ๊ฒŒ ๋งŒ๋“ค๋ฉฐ, ๋ฉ”๋ชจ๋ฆฌ ์‚ฌ์šฉ๋Ÿ‰์„ ๋Š˜๋ฆฌ๊ณ  ์„ฑ๋Šฅ์„ ๋–จ์–ด๋œจ๋ฆฐ๋‹ค. JVM์˜ ๊ฐ€๋น„์ง€ ์ปฌ๋ ‰ํ„ฐ๋Š” ์ƒ๋‹นํžˆ ์ตœ์ ํ™”๊ฐ€ ์ž˜๋˜์–ด์žˆ์–ด ์ง์ ‘ ๋งŒ๋“  ๊ฐ์ฒด ํ’€๋ณด๋‹ค ํ›จ์”ฌ ๋น ๋ฅธ ๊ฒฝ์šฐ๊ฐ€ ๋งŽ๋‹ค. ๋ฐฉ์–ด์  ๋ณต์‚ฌ๊ฐ€ ํ•„์š”ํ•œ ์ƒํ™ฉ์—์„œ ๊ฐ์ฒด๋ฅผ ์žฌ์‚ฌ์šฉํ–ˆ์„ ๋•Œ์˜ ํ”ผํ•ด๊ฐ€ ํ•„์š” ์—†๋Š” ๊ฐ์ฒด๋ฅผ ๋ฐ˜๋ณต ์ƒ์„ฑํ–ˆ์„ ๋•Œ์˜ ํ”ผํ•ด๋ณด๋‹ค ํ›จ์”ฌ ํฐ ๊ฒƒ์„ ์œ ์˜ํ•ด์•ผํ•œ๋‹ค.

Last updated