Item 37. EnumMap

ordinal ์ธ๋ฑ์‹ฑ ๋Œ€์‹  EnumMap์„ ์‚ฌ์šฉํ•˜๋ผ.

๋ฐฐ์—ด์ด๋‚˜ ๋ฆฌ์ŠคํŠธ์—์„œ ์›์†Œ๋ฅผ ๊บผ๋‚ผ ๋•Œ ordinal ๋ฉ”์„œ๋“œ๋กœ ์ธ๋ฑ์Šค๋ฅผ ์–ป์„ ์ˆ˜ ์žˆ์ง€๋งŒ, ๋ณดํ†ต ์ด๋Ÿฐ ์šฉ๋„๋กœ ordinal์„ ์“ฐ๋Š” ๊ฒƒ์€ ์ข‹์ง€ ์•Š๋‹ค.

ordinal

class Plant {
    enum LifeCycle {ANNUAL, PERENNIAL, BIENNIAL}

    final String name;
    final LifeCycle lifeCycle;

    Plant(String name, LifeCycle lifeCycle) {
        this.name = name;
        this.lifeCycle = lifeCycle;
    }

    @Override
    public String toString() {
        return name;
    }
}

class Main {
    public static void main(String[] args) {
        Set<Plant>[] plantsByLifeCycle = (Set<Plant>[]) new Set[Plant.LifeCycle.values().length]; // ๋น„๊ฒ€์‚ฌ ํ˜•๋ณ€ํ™˜ ๊ฒฝ๊ณ 
        List<Plant> garden = List.of(
                new Plant("๋ฐ”์งˆ", Plant.LifeCycle.ANNUAL),
                new Plant("์บ๋Ÿฌ์›จ์ด", Plant.LifeCycle.BIENNIAL),
                new Plant("๋”œ", Plant.LifeCycle.ANNUAL),
                new Plant("๋ผ๋ฒค๋”", Plant.LifeCycle.PERENNIAL),
                new Plant("ํŒŒ์Šฌ๋ฆฌ", Plant.LifeCycle.BIENNIAL),
                new Plant("๋กœ์ฆˆ๋งˆ๋ฆฌ", Plant.LifeCycle.PERENNIAL)
        );

        for (int i = 0; i < plantsByLifeCycle.length; i++) {
            plantsByLifeCycle[i] = new HashSet<>();
        }

        for (Plant p : garden) {
            plantsByLifeCycle[p.lifeCycle.ordinal()].add(p);
        }

        for (int i = 0; i < plantsByLifeCycle.length; i++) {
            // ๋ฐฐ์—ด์€ ์ธ๋ฑ์Šค์˜ ์˜๋ฏธ๋ฅผ ๋ชจ๋ฅด๊ธฐ ๋•Œ๋ฌธ์— ์ถœ๋ ฅํ•  ๋•Œ ๋งˆ๋‹ค LifeCycle.values()๋ฅผ ํ˜ธ์ถœํ•ด์•ผ ํ•œ๋‹ค.
            System.out.printf("%s: %s%n", Plant.LifeCycle.values()[i], plantsByLifeCycle[i]); // ArrayIndexOutOfBoundsException ๋ฐœ์ƒ ๊ฐ€๋Šฅ
        }
    }
}

EnumMap

์œ„ ๋ฐฉ์‹์€ ๋™์ž‘์€ ํ•˜์ง€๋งŒ ์ฃผ์„์— ์ ํžŒ ๋Œ€๋กœ ๋ฌธ์ œ๊ฐ€ ๋งŽ๋‹ค. ์œ„ ๋ฐฉ์‹์ด ์•„๋‹Œ EnumMap์„ ์‚ฌ์šฉํ•˜๋ฉด ์ด๋Ÿฐ ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•  ์ˆ˜ ์žˆ๋‹ค.

class Main {
    public static void main(String[] args) {
        Map<Plant.LifeCycle, Set<Plant>> plantsByLifeCycle = new EnumMap<>(Plant.LifeCycle.class); // ํ˜•๋ณ€ํ™˜ ์—†์ด ์•ˆ์ „ํ•˜๊ฒŒ ์„ ์–ธ

        List<Plant> garden = List.of(
                new Plant("๋ฐ”์งˆ", Plant.LifeCycle.ANNUAL),
                new Plant("์บ๋Ÿฌ์›จ์ด", Plant.LifeCycle.BIENNIAL),
                new Plant("๋”œ", Plant.LifeCycle.ANNUAL),
                new Plant("๋ผ๋ฒค๋”", Plant.LifeCycle.PERENNIAL),
                new Plant("ํŒŒ์Šฌ๋ฆฌ", Plant.LifeCycle.BIENNIAL),
                new Plant("๋กœ์ฆˆ๋งˆ๋ฆฌ", Plant.LifeCycle.PERENNIAL)
        );

        for (Plant.LifeCycle lc : Plant.LifeCycle.values()) {
            plantsByLifeCycle.put(lc, new HashSet<>());
        }

        for (Plant p : garden) {
            plantsByLifeCycle.get(p.lifeCycle).add(p);
        }

        for (Plant.LifeCycle lifeCycle : plantsByLifeCycle.keySet()) {
            // ํ‚ค๋ฅผ ์ง์ ‘ ์‚ฌ์šฉํ•ด ์ˆœํšŒํ•˜๋ฉด ordinal ๋ฉ”์„œ๋“œ๋ฅผ ์‚ฌ์šฉํ•˜์ง€ ์•Š์•„๋„ ๋œ๋‹ค.
            System.out.printf("%s: %s%n", lifeCycle, plantsByLifeCycle.get(lifeCycle)); // ์ธ๋ฑ์Šค๋ฅผ ์‚ฌ์šฉํ•˜์ง€ ์•Š๊ณ ๋„ ์ถœ๋ ฅ ๊ฐ€๋Šฅ
        }
    }
}

์ด์™€ ๊ฐ™์ด EnumMap์„ ์‚ฌ์šฉํ•˜๋ฉด ์„ฑ๋Šฅ ์ €ํ•˜๋„ ์—†๊ณ , ํƒ€์ž… ์•ˆ์ „์„ฑ๋„ ํ™•๋ณดํ•  ์ˆ˜ ์žˆ๋‹ค. (๋‚ด๋ถ€์—์„œ ๋ฐฐ์—ด์„ ์‚ฌ์šฉํ•˜๊ธฐ ๋•Œ๋ฌธ์ด๋ฉฐ, ๋‚ด๋ถ€ ๊ตฌํ˜„ ๋ฐฉ์‹์„ ์•ˆ์œผ๋กœ ์ˆจ๊ฒจ์„œ ํƒ€์ž… ์•ˆ์ „์„ฑ์„ ํ™•๋ณดํ•œ๋‹ค.)

์—ด๊ฑฐ ํƒ€์ž… ๊ฐ’๋“ค ๋งคํ•‘ ์˜ˆ์‹œ

์ด๋ฒˆ์—” ๋‘ ์—ด๊ฑฐ ํƒ€์ž… ๊ฐ’๋“ค์„ ๋งคํ•‘ํ•˜์—ฌ ๋กœ์ง์„ ๊ตฌํ˜„ํ•ด์•ผํ•˜๋Š” ๊ฒฝ์šฐ๋ฅผ ์‚ดํŽด๋ณด๋ฉด ์•„๋ž˜์™€ ๊ฐ™์ด ๊ตฌํ˜„ํ•  ์ˆ˜ ์žˆ๋‹ค.

enum Phase {
    SOLID, LIQUID, GAS;

    public enum Transition {
        MELT, FREEZE, BOIL, CONDENSE, SUBLIME, DEPOSIT;

        // ํ–‰: from, ์—ด: to, ์ƒํƒœ๊ฐ€ ๋Š˜์–ด๋‚˜๋Š” ๋งŒํผ ์ด์ฐจ์› ๋ฐฐ์—ด์ด ์ปค์ง„๋‹ค.
        private static final Transition[][] TRANSITIONS = {
                {null, MELT, SUBLIME},
                {FREEZE, null, BOIL},
                {DEPOSIT, CONDENSE, null}
        };

        // ๋‹ค๋ฅธ ์ƒํƒœ๋กœ ์ „์ดํ•˜๋Š” ๋ฉ”์„œ๋“œ
        public static Transition from(Phase from, Phase to) {
            // ordinal ๋ฉ”์„œ๋“œ๋ฅผ ์‚ฌ์šฉํ•ด ์ธ๋ฑ์Šค๋ฅผ ์–ป๋Š”๋‹ค, ์ด๋Š” ์œ„์—์„œ ์‚ดํŽด๋ณธ ๊ฒƒ์ฒ˜๋Ÿผ ์ข‹์ง€ ์•Š์€ ๋ฐฉ์‹์ด๋‹ค.
            return TRANSITIONS[from.ordinal()][to.ordinal()];
        }
    }
}

์œ„์™€ ๊ฐ™์ด ๊ตฌํ˜„ํ•˜๋ฉด ์ƒํƒœ๊ฐ€ ๋Š˜์–ด๋‚  ๋•Œ๋งˆ๋‹ค ์ด์ฐจ์› ๋ฐฐ์—ด์˜ ํฌ๊ธฐ๊ฐ€ ์ปค์ง€๊ธฐ ๋•Œ๋ฌธ์— ๋ฉ”๋ชจ๋ฆฌ ๋‚ญ๋น„๊ฐ€ ์‹ฌํ•ด์ง€๋Š” ๊ฒƒ ๋ฟ๋งŒ ์•„๋‹ˆ๋ผ ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ•  ๊ฐ€๋Šฅ์„ฑ๋„ ๋†’์•„์ง„๋‹ค.

enum Phase {
    SOLID, LIQUID, GAS; // + PLASMA

    public enum Transition {
        MELT(SOLID, LIQUID), FREEZE(LIQUID, SOLID),
        BOIL(LIQUID, GAS), CONDENSE(GAS, LIQUID),
        SUBLIME(SOLID, GAS), DEPOSIT(GAS, SOLID);
        // + IONIZE(GAS, PLASMA), DEIONIZE(PLASMA, GAS);

        // ์ƒ์ „์ด ๋งต ์ดˆ๊ธฐํ™”
        private static final Map<Phase, Map<Phase, Transition>> m = Stream.of(values())
                .collect(groupingBy(t -> t.from,
                        () -> new EnumMap<>(Phase.class),
                        toMap(t -> t.to,
                                t -> t,
                                (x, y) -> y,
                                () -> new EnumMap<>(Phase.class))));

        private final Phase from;
        private final Phase to;

        Transition(Phase from, Phase to) {
            this.from = from;
            this.to = to;
        }

        public static Transition from(Phase from, Phase to) {
            return m.get(from).get(to);
        }
    }
}

ํ•˜์ง€๋งŒ EnumMap์„ ์‚ฌ์šฉํ•˜๋ฉด ์ดˆ๊ธฐํ™” ๊ณผ์ •์ด ๋‹ค์†Œ ๋ณต์žกํ•ด์ง€์ง€๋งŒ, ์ด์ฐจ์› ๋ฐฐ์—ด์„ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ๋ณด๋‹ค ํ›จ์”ฌ ์•ˆ์ •์ ์ด๊ณ  ์œ ์—ฐํ•˜๊ฒŒ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค. ๋งŒ์•ฝ ์ƒˆ๋กœ์šด ์ƒํƒœ์ธ PLASMA๊ฐ€ ์ถ”๊ฐ€๋˜๋”๋ผ๋„ ์ฃผ์„๊ณผ ๊ฐ™์ด ์ƒํƒœ์™€ ์ „์ด ๋ชฉ๋ก์—๋งŒ ์ถ”๊ฐ€ํ•˜๊ณ , ๋‚˜๋จธ์ง€ ์ฝ”๋“œ๋Š” ์ˆ˜์ •ํ•  ํ•„์š”๊ฐ€ ์—†๋‹ค.

Last updated

Was this helpful?