Item 17. Minimize Mutability

๋ณ€๊ฒฝ ๊ฐ€๋Šฅ์„ฑ์„ ์ตœ์†Œํ™”ํ•˜๋ผ

๋ถˆ๋ณ€ ์ธ์Šคํ„ด์Šค๋กœ ์ƒ์„ฑ๋œ ์ •๋ณด๋Š” ๊ฐ์ฒด๊ฐ€ ์†Œ๋ฉธํ•˜๋Š” ์ˆœ๊ฐ„๊นŒ์ง€ ์ ˆ๋Œ€ ๋‹ฌ๋ผ์ง€์ง€ ์•Š๋Š”๋‹ค. ์ด ํŠน์ง•์€ ๊ฐ€๋ณ€ ํด๋ž˜์Šค๋ณด๋‹ค ์„ค๊ณ„ํ•˜๊ณ  ๊ตฌํ˜„ํ•˜๊ธฐ ์‰ฝ๊ณ , ์˜ค๋ฅ˜๊ฐ€ ์ƒ๊ธธ ์—ฌ์ง€๋„ ์ ๊ณ , ํ›จ์”ฌ ์•ˆ์ „ํ•˜๊ฒŒ ํ•ด์ค€๋‹ค.

๋ถˆ๋ณ€ ํด๋ž˜์Šค ์ƒ์„ฑ์˜ 5๊ฐ€์ง€ ๊ทœ์น™

๊ฐ„๋‹จํžˆ ๋งํ•˜๋ฉด ์œ„์— ์„ค๋ช…ํ•œ ๊ฒƒ๊ณผ ๊ฐ™์ด ์ƒ์„ฑ๋œ ์‹œ์ ๋ถ€ํ„ฐ ์†Œ๋ฉธ๋  ๋•Œ๊นŒ์ง€ ์ ˆ๋Œ€ ๋‹ฌ๋ผ์ง€์ง€ ์•Š๋„๋ก ํ•˜๋ฉด ๋œ๋‹ค.

  1. ๊ฐ์ฒด์˜ ์ƒํƒœ๋ฅผ ๋ณ€๊ฒฝํ•˜๋Š” ๋ฉ”์„œ๋“œ(๋ณ€๊ฒฝ์ž) ์ œ๊ณต X

  2. ํด๋ž˜์Šค ํ™•์žฅ ๊ธˆ์ง€

    • ๊ฐ€์žฅ ์‰ฌ์šด ๋ฐฉ๋ฒ•์€ ํด๋ž˜์Šค๋ฅผ final๋กœ ์„ ์–ธํ•˜์—ฌ ํ•˜์œ„ ํด๋ž˜์Šค ์ƒ์„ฑ์„ ๋ง‰๋Š” ๊ฒƒ์ด ์กด์žฌ

    • ๋ชจ๋“  ์ƒ์„ฑ์ž๋ฅผ private ํ˜น์€ package-private์œผ๋กœ ์„ ์–ธํ•œ ๋’ค, public ์ •์  ํŒฉํ„ฐ๋ฆฌ ๋ฉ”์„œ๋“œ๋ฅผ ์ œ๊ณตํ•˜๋Š” ๋ฐฉ๋ฒ•๋„ ์กด์žฌ(๋” ์œ ์—ฐํ•œ ๋ฐฉ๋ฒ•)

  3. ๋ชจ๋“  ํ•„๋“œ final ์„ ์–ธ

  4. ๋ชจ๋“  ํ•„๋“œ private ์„ ์–ธ

  5. ์ž์‹  ์™ธ ๋‚ด๋ถ€์˜ ๊ฐ€๋ณ€ ์ปดํฌ๋„ŒํŠธ์— ๋Œ€ํ•œ ์ ‘๊ทผ ์ œ๊ณต X

    • ํด๋ผ์ด์–ธํŠธ๊ฐ€ ์ œ๊ณตํ•œ ๊ฐ์ฒด ์ฐธ์กฐ ๋ฐ˜ํ™˜ X

    • ์ ‘๊ทผ์ž ๋ฉ”์„œ๋“œ๊ฐ€ ๊ฐ€๋ณ€ ๊ฐ์ฒด ์ฐธ์กฐ ์ง์ ‘ ๋ฐ˜ํ™˜ X

    • ์ƒ์„ฑ์ž / ์ ‘๊ทผ์ž / readObject ๋ฉ”์„œ๋“œ์—์„œ ๊ฐ€๋ณ€ ๊ฐ์ฒด ์ฐธ์กฐ๋ฅผ ๋ฐฉ์–ด์ ์œผ๋กœ ๋ณต์‚ฌ๋ฅผ ์ˆ˜ํ–‰ํ•ด์•ผ ํ•จ

์œ„์˜ ๊ทœ์น™์„ ์ง€ํ‚จ ์˜ˆ์‹œ ์ฝ”๋“œ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™๋‹ค.

public final class Complex { // 2. final ์„ ์–ธํ•˜์—ฌ ํ•˜์œ„ ํด๋ž˜์Šค ์ƒ์„ฑ ๊ธˆ์ง€

    // 3, 4. ๋ชจ๋“  ํ•„๋“œ final / private ์„ ์–ธ
    private final double re;
    private final double im;

    public Complex(double re, double im) {
        this.re = re;
        this.im = im;
    }

    // 1. ๊ฐ์ฒด์˜ ์ƒํƒœ๋ฅผ ๋ณ€๊ฒฝํ•˜๋Š” ๋ฉ”์„œ๋“œ(๋ณ€๊ฒฝ์ž) ์ œ๊ณต X
    public double realPart() {
        return re;
    }

    public double imaginaryPart() {
        return im;
    }

    public Complex plus(Complex c) {
        return new Complex(re + c.re, im + c.im); // 5. ์ƒˆ๋กœ์šด ์ธ์Šคํ„ด์Šค๋ฅผ ์ƒ์„ฑํ•˜์—ฌ ์›๋ž˜ ์ธ์Šคํ„ด์Šค์˜ ๊ฐ’์„ ๋ณ€๊ฒฝํ•˜์ง€ ์•Š์Œ, ์•„๋ž˜ ๋ฉ”์„œ๋“œ๋“ค๋„ ๋™์ผ
    }

    public Complex minus(Complex c) {
        return new Complex(re - c.re, im - c.im);
    }

    public Complex times(Complex c) {
        return new Complex(re * c.re - im * c.im, re * c.im + im * c.re);
    }

    public Complex dividedBy(Complex c) {
        double tmp = c.re * c.re + c.im * c.im;
        return new Complex((re * c.re + im * c.im) / tmp, (im * c.re - re * c.im) / tmp);
    }

    // equals / hashCode / toString ...
}

์—ฌ๊ธฐ์„œ ์‚ฌ์น™ ์—ฐ์‚ฐ ๋ฉ”์„œ๋“œ(plus, minus, times, dividedBy)๋Š” ๋ชจ๋‘ ์ƒˆ๋กœ์šด ์ธ์Šคํ„ด์Šค๋ฅผ ์ƒ์„ฑํ•˜์—ฌ ์›๋ž˜ ์ธ์Šคํ„ด์Šค์˜ ๊ฐ’์„ ๋ณ€๊ฒฝํ•˜์ง€ ์•Š๊ณ , ์ƒˆ๋กœ์šด ์ธ์Šคํ„ด์Šค๋ฅผ ๋ฐ˜ํ™˜ํ•œ๋‹ค. ๋•Œ๋ฌธ์— ๋ฉ”์„œ๋“œ ์ด๋ฆ„๋„ add๊ฐ™์€ ๋™์‚ฌ๊ฐ€ ์•„๋‹Œ plus๊ฐ™์€ ์ „์น˜์‚ฌ๋ฅผ ์‚ฌ์šฉํ•œ ๊ฒƒ๋„ ์•Œ ์ˆ˜ ์žˆ๋‹ค.(BigInteger, BigDecimal ํด๋ž˜์Šค๋Š” ํ•ด๋‹น ๋ช…๋ช… ๊ทœ์น™์„ ์ง€ํ‚ค์ง€ ์•Š์•„ ํ˜ผ๋ž€์„ ์ฃผ๊ณ  ์žˆ๋‹ค.)

๋ถˆ๋ณ€ ํด๋ž˜์Šค์˜ ์žฅ์ 

์Šค๋ ˆ๋“œ ์•ˆ์ „๊ณผ ์ธ์Šคํ„ด์Šค ์บ์‹ฑ

๊ทผ๋ณธ์ ์œผ๋กœ ๋ณ€ํ•˜์ง€ ์•Š์•„ ์Šค๋ ˆ๋“œ ์•ˆ์ „ํ•˜๊ธฐ ๋•Œ๋ฌธ์— ๋”ฐ๋กœ ๋™๊ธฐํ™”ํ•  ํ•„์š”๊ฐ€ ์—†์–ด ์—ฌ๋Ÿฌ ์Šค๋ ˆ๋“œ๊ฐ€ ๋™์‹œ์— ์‚ฌ์šฉํ•ด๋„ ์•ˆ์ „ํ•˜๋‹ค. ๋ถˆ๋ณ€ ๊ฐ์ฒด๋กœ ๋งŒ๋“ค์–ด ๋†“๋Š” ๊ฒƒ์ด ์Šค๋ ˆ๋“œ ์•ˆ์ „์„ฑ์„ ์–ป์„ ์ˆ˜ ์žˆ๋Š” ๊ฐ€์žฅ ์‰ฌ์šด ๋ฐฉ๋ฒ•์ด๊ธฐ๋„ ํ•˜๋‹ค.

๋ถˆ๋ณ€๊ฐ์ฒด๋Š” ๋‹ค๋ฅธ ์Šค๋ ˆ๋“œ์— ์˜ํ–ฅ์„ ์ฃผ์ง€ ์•Š๊ธฐ ๋•Œ๋ฌธ์— ์ด๋Ÿฌํ•œ ์žฅ์ ์„ ์‚ด๋ ค ํ•œ ๋ฒˆ ๋งŒ๋“  ์ธ์Šคํ„ด์Šค๋ฅผ ์ค‘๋ณต ์ƒ์„ฑํ•˜์ง€ ์•Š๊ณ  ์žฌํ™œ์šฉํ•˜๋Š” ๊ฒƒ์ด ๊ฐ€๋Šฅํ•˜๋‹ค. ์•„๋ž˜ ๋‘ ๊ฐ€์ง€ ๋ฐฉ๋ฒ•์œผ๋กœ ์ œ๊ณตํ•ด์ค„ ์ˆ˜ ์žˆ๋Š”๋ฐ, 2๋ฒˆ์„ ์‚ฌ์šฉํ•˜๊ฒŒ ๋˜๋ฉด ํด๋ผ์ด์–ธํŠธ๋ฅผ ์ˆ˜์ •ํ•˜์ง€ ์•Š๊ณ  ํ•„์š”์— ๋”ฐ๋ผ ๋ถˆ๋ณ€ ๊ฐ์ฒด๋ฅผ ์บ์‹ฑํ•˜์—ฌ ์žฌํ™œ์šฉํ•  ์ˆ˜ ์žˆ๋Š” ์žฅ์ ์ด ์ƒ๊ธด๋‹ค.

// 1. public static final ํ•„๋“œ๋กœ ๋ถˆ๋ณ€ ๊ฐ์ฒด ์ƒ์„ฑ
public final class Complex {
    public static final Complex ZERO = new Complex(0, 0);
    public static final Complex ONE = new Complex(1, 0);
    public static final Complex I = new Complex(0, 1);
    // ...
}

// 2. ์ •์  ํŒฉํ„ฐ๋ฆฌ ๋ฉ”์„œ๋“œ๋กœ ๋ถˆ๋ณ€ ๊ฐ์ฒด ์ƒ์„ฑ
public final class Integer extends Number implements Comparable<Integer> {
    // ...

    @HotSpotIntrinsicCandidate
    public static Integer valueOf(int i) {
        if (i >= IntegerCache.low && i <= IntegerCache.high)
            return IntegerCache.cache[i + (-IntegerCache.low)];
        return new Integer(i);
    }
    // ...
}

๋‚ด๋ถ€ ๋ฐ์ดํ„ฐ ๊ณต์œ 

๋ถˆ๋ณ€ ๊ฐ์ฒด๋ผ๋ฆฌ๋Š” ๋‚ด๋ถ€ ๋ฐ์ดํ„ฐ๋ฅผ ๊ณต์œ ํ•˜์—ฌ ๋ณต์‚ฌํ•˜์ง€ ์•Š๊ณ  ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.

public class BigInteger extends Number implements Comparable<BigInteger> {

    final int signum; // ๋ถ€ํ˜ธ
    final int[] mag; // ์ ˆ๋Œ“๊ฐ’, ๋ฐฐ์—ด์ด๊ธฐ ๋•Œ๋ฌธ์— ๊ฐ€๋ณ€

    // ...

    public BigInteger negate() {
        return new BigInteger(this.mag, -this.signum); // ๋ณต์‚ฌํ•˜์ง€ ์•Š๊ณ  ๊ทธ๋Œ€๋กœ ์‚ฌ์šฉํ•˜์—ฌ, ์ƒˆ๋กœ ์ƒ์„ฑ๋œ ์ธ์Šคํ„ด์Šค์™€ ๋‚ด๋ถ€ ๋ฐฐ์—ด์„ ๊ณต์œ  
    }
}

๋ถˆ๋ณ€ ๊ฐ์ฒด์ด๊ธฐ ๋•Œ๋ฌธ์— ๊ฐ€๋ณ€ ๊ฐ์ฒด์ธ ๋‚ด๋ถ€ ๋ฐฐ์—ด์ด ๋ณ€๊ฒฝ๋˜์ง€ ์•Š๋Š”๋‹ค๋Š” ๊ฒƒ์„ ๋ณด์žฅํ•  ์ˆ˜ ์žˆ๊ธฐ ๋•Œ๋ฌธ์— ๊ฐ€๋Šฅํ•œ ๋ฐฉ๋ฒ•์ด๋‹ค.

์‹คํŒจ ์›์ž์„ฑ ์ œ๊ณต

๋‚ด๋ถ€ ์ƒํƒœ๋ฅผ ๋ฐ”๊พธ์ง€ ์•Š๊ธฐ ๋•Œ๋ฌธ์— ๋ฉ”์„œ๋“œ์—์„œ ์˜ˆ์™ธ๊ฐ€ ๋ฐœ์ƒํ•œ ํ›„์—๋„ ๊ทธ ๊ฐ์ฒด๋Š” ์—ฌ์ „ํžˆ ์œ ํšจํ•œ ์ƒํƒœ์—ฌ์•ผ ํ•œ๋‹ค(์‹คํŒจ ์›์ž์„ฑ)๋Š” ๊ทœ์น™์„ ์ž์—ฐ์Šค๋Ÿฝ๊ฒŒ ๋”ฐ๋ฅด๊ฒŒ ๋œ๋‹ค.

๋ถˆ๋ณ€ ํด๋ž˜์Šค์˜ ๋‹จ์ 

์žฅ์ ์ด์ž ๋‹จ์ ์ธ ๋ถ€๋ถ„์œผ๋กœ, ๊ฐ’์„ ์•„์ฃผ ์กฐ๊ธˆ ๋ณ€๊ฒฝํ•˜๊ธฐ ์œ„ํ•ด์„œ๋„ ์ƒˆ๋กœ์šด ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ•ด์•ผ ํ•œ๋‹ค๋Š” ์ ์ด๋‹ค. ์ด ๋ฌธ์ œ๋ฅผ ๋Œ€์ฒ˜ํ•˜๊ธฐ ์œ„ํ•ด, ๊ฐ€๋ณ€ ๋™๋ฐ˜ ํด๋ž˜์Šค๋ฅผ ๋งŒ๋“ค์–ด ๋ถˆ๋ณ€ ํด๋ž˜์Šค์˜ ๋‹จ์ ์ด ์กด์žฌํ•˜๋‚˜ ์—ฐ์‚ฐ๋งˆ๋‹ค ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ•˜์ง€ ์•Š๋Š” ๊ฐ€๋ณ€ ๋™๋ฐ˜ ํด๋ž˜์Šค๋กœ ํ•ด๊ฒฐํ•  ์ˆ˜ ์žˆ๋‹ค.

  • ํด๋ผ์ด์–ธํŠธ๊ฐ€ ์‚ฌ์šฉํ•  ์—ฐ์‚ฐ์„ ์˜ˆ์ธก ๊ฐ€๋Šฅํ•œ ๊ฒฝ์šฐ: package-private์— ๊ฐ€๋ณ€ ๋™๋ฐ˜ ํด๋ž˜์Šค๋ฅผ ๋‘์–ด ์—ฐ์‚ฐ์„ ์ˆ˜ํ–‰(BigInteger)

  • ํด๋ผ์ด์–ธํŠธ๊ฐ€ ์‚ฌ์šฉํ•  ์—ฐ์‚ฐ์„ ์˜ˆ์ธกํ•  ์ˆ˜ ์—†๋Š” ๊ฒฝ์šฐ: StringBuilder์™€ ๊ฐ™์€ ๋ณ„๋„์˜ ๊ฐ€๋ณ€ ๋™๋ฐ˜ ํด๋ž˜์Šค๋ฅผ ์ œ๊ณต

Last updated