πŸ‘¨πŸ»β€πŸ’» μ΄νŽ™ν‹°λΈŒ μžλ°” - μ—΄κ±° νƒ€μž…κ³Ό μ• λ„ˆν…Œμ΄μ…˜

PeterΒ·2022λ…„ 3μ›” 20일
0
post-thumbnail

6μž₯ - μ—΄κ±° νƒ€μž…κ³Ό μ• λ„ˆν…Œμ΄μ…˜


πŸ’‘ int μƒμˆ˜ λŒ€μ‹  μ—΄κ±° νƒ€μž…μ„ μ‚¬μš©ν•˜λΌ

β€œμ—΄κ±° νƒ€μž…μ€ μ •μˆ˜ μƒμˆ˜λ³΄λ‹€ 더 읽기 쉽고 μ•ˆμ „ν•˜κ³  κ°•λ ₯ν•˜λ‹€β€

1. μ •μˆ˜ μ—΄κ±° νŒ¨ν„΄

public static final int APPLE_FUJI = 0;
public static final int APPLE_PIPPIN = 1;
public static final int APPLE_GRANNY_SMITH = 2;

public static final int ORANGE_NAVEL = 0;
public static final int ORANGE_TEMPLE = 1;
public static final int ORANGE_BLOOD = 2;
  • μ •μˆ˜ μ—΄κ±° νŒ¨ν„΄(int enum pattern)의 문제점
    1. νƒ€μž… μ•ˆμ „μ„ 보μž₯ν•  방법이 μ—†μŒ
    2. ν‘œν˜„λ ₯도 쒋지 μ•ŠμŒ
    • ex) μ˜€λ Œμ§€λ₯Ό 건넀야 ν•  λ©”μ„œλ“œμ— 사과λ₯Ό 보내고 동등 μ—°μ‚°μž(==)둜 λΉ„κ΅ν•˜λ”λΌλ„ μ»΄νŒŒμΌλŸ¬λŠ” μ•„λ¬΄λŸ° κ²½κ³  λ©”μ‹œμ§€λ₯Ό 좜λ ₯ν•˜μ§€ μ•ŠμŒ.
  • μžλ°”κ°€ μ •μˆ˜ μ—΄κ±° νŒ¨ν„΄μ„ μœ„ν•œ λ³„λ„μ˜ 이름곡간(namespace)λ₯Ό μ§€μ›ν•˜μ§€ μ•ŠκΈ° λ•Œλ¬Έμ— μ–΄μ©” 수 없이 APPLE, ORANGE λ“±μ˜ 접두어λ₯Ό μ‚¬μš©ν•΄μ„œ 이름 μΆ©λŒμ„ 방지해야 함.
  • μ •μˆ˜ λŒ€μ‹  λ¬Έμžμ—΄ μƒμˆ˜λ₯Ό μ‚¬μš©ν•˜λŠ” λ¬Έμžμ—΄ μ—΄κ±° νŒ¨ν„΄(string enum pattern)은 더 λ‚˜μ¨.
    • λ¬Έμžμ—΄ μƒμˆ˜μ˜ 이름 λŒ€μ‹  λ¬Έμžμ—΄ 값을 κ·ΈλŒ€λ‘œ ν•˜λ“œμ½”λ”©ν•˜κ²Œ λ§Œλ“€κΈ° λ•Œλ¬Έ
    • ν•˜λ“œμ½”λ”©ν•œ λ¬Έμžμ—΄μ— μ˜€νƒ€κ°€ μžˆμ–΄λ„ μ»΄νŒŒμΌλŸ¬λŠ” 확인할 길이 μ—†μœΌλ―€λ‘œ μžμ—°μŠ€λŸ½κ²Œ λŸ°νƒ€μž„ 버그가 생김

2. μ—΄κ±° νƒ€μž…

public enum Apple { FUJI, PIPPIN, GRANNY_SMITH }
public enum Orange { NEVEL, TEMPLE, BLOOD }
  • μ—΄κ±° νƒ€μž… μ„€λͺ…
    • μ™„μ „ν•œ ν˜•νƒœμ˜ 클래슀이며 μƒμˆ˜ ν•˜λ‚˜λ‹Ή μžμ‹ μ˜ μΈμŠ€ν„΄μŠ€λ₯Ό ν•˜λ‚˜μ”© λ§Œλ“€μ–΄ public static final ν•„λ“œλ‘œ κ³΅κ°œν•¨.
    • λ°–μ—μ„œ μ ‘κ·Όν•  수 μžˆλŠ” μƒμ„±μžλ₯Ό μ œκ³΅ν•˜μ§€ μ•ŠμœΌλ―€λ‘œ 사싀상 finalμž„.
    • 싱글턴을 μΌλ°˜ν™”ν•œ ν˜•νƒœ, 싱글턴은 μ›μ†Œκ°€ ν•˜λ‚˜μΈ μ—΄κ±°νƒ€μž….
  • μ—΄κ±° νƒ€μž…μ˜ μž₯점
    • μ—΄κ±° νƒ€μž…μ€ 컴파일 νƒ€μž„ μ•ˆμ „μ„±μ„ μ œκ³΅ν•¨.
    • 각자의 이름곡간이 μžˆμ–΄μ„œ 이름이 같은 μƒμˆ˜λ„ ν‰ν™”λ‘­κ²Œ 곡쑴함.
    • μ—΄κ±° νƒ€μž…μ—λŠ” μž„μ˜μ˜ λ©”μ„œλ“œλ‚˜ ν•„λ“œλ₯Ό μΆ”κ°€ν•  수 있고, μž„μ˜μ˜ μΈν„°νŽ˜μ΄μŠ€λ₯Ό κ΅¬ν˜„ν•˜κ²Œ ν•  μˆ˜λ„ 있음
  • 데이터와 λ©”μ„œλ“œλ₯Ό κ°–λŠ” μ—΄κ±° νƒ€μž…
    • μ—΄κ±° νƒ€μž… μƒμˆ˜ 각각을 νŠΉμ • 데이터와 μ—°κ²°μ§€μœΌλ €λ©΄ μƒμ„±μžμ—μ„œ 데이터λ₯Ό λ°›μ•„ μΈμŠ€ν„΄μŠ€ ν•„λ“œμ— μ €μž₯ν•˜λ©΄ 됨.
    • μ—΄κ±° νƒ€μž…μ€ 근본적으둜 λΆˆλ³€μ΄λ―€λ‘œ λͺ¨λ“  ν•„λ“œλŠ” final이어야 함.
// 데이터와 λ©”μ„œλ“œλ₯Ό κ°–λŠ” μ—΄κ±° νƒ€μž…
public enum Planet {
    MERCURY(3.302e+23, 2.439e6),
    VENUS  (4.869e+24, 6.052e6),
    EARTH  (5.975e+24, 6.378e6),
    MARS   (6.419e+23, 3.393e6),
    JUPITER(1.899e+27, 7.149e7),
    SATURN (5.685e+26, 6.027e7),
    URANUS (8.683e+25, 2.556e7),
    NEPTUNE(1.024e+26, 2.477e7);

    private final double mass;           // μ§ˆλŸ‰(λ‹¨μœ„: ν‚¬λ‘œκ·Έλž¨)
    private final double radius;         // λ°˜μ§€λ¦„(λ‹¨μœ„: λ―Έν„°)
    private final double surfaceGravity; // ν‘œλ©΄μ€‘λ ₯(λ‹¨μœ„: m / s^2)

    // 쀑λ ₯μƒμˆ˜(λ‹¨μœ„: m^3 / kg s^2)
    private static final double G = 6.67300E-11;

    // μƒμ„±μž
    Planet(double mass, double radius) {
        this.mass = mass;
        this.radius = radius;
        surfaceGravity = G * mass / (radius * radius);
    }

    public double mass()           { return mass; }
    public double radius()         { return radius; }
    public double surfaceGravity() { return surfaceGravity; }

    public double surfaceWeight(double mass) {
        return mass * surfaceGravity;  // F = ma
    }
}
  • μƒμˆ˜λ³„ λ©”μ„œλ“œ κ΅¬ν˜„μ„ ν™œμš©ν•œ μ—΄κ±° νƒ€μž…
    • μƒμˆ˜λ³„λ‘œ λ‹€λ₯΄κ²Œ λ™μž‘ν•˜λŠ” μ½”λ“œλ₯Ό κ΅¬ν˜„ν•˜κ³ μž ν•  λ•Œ μƒμˆ˜λ³„ λ©”μ„œλ“œ κ΅¬ν˜„(constant-specific method implementation)을 μ‚¬μš©ν•˜λ©΄ 됨.
    • μ•„λž˜ μ˜ˆμ‹œμ—μ„œλŠ” applyλΌλŠ” 좔상 λ©”μ„œλ“œλ₯Ό μ„ μ–Έν•˜κ³  각 μƒμˆ˜λ³„ 클래슀 λͺΈμ²΄, 즉 각 μƒμˆ˜μ—μ„œ μžμ‹ μ— 맞게 μž¬μ •μ˜ν•˜μ˜€μŒ.
// μƒμˆ˜λ³„ 클래슀 λͺΈμ²΄(class body)와 데이터λ₯Ό μ‚¬μš©ν•œ μ—΄κ±° νƒ€μž…
public enum Operation {
    PLUS("+") {
        public double apply(double x, double y) { return x + y; }
    },
    MINUS("-") {
        public double apply(double x, double y) { return x - y; }
    },
    TIMES("*") {
        public double apply(double x, double y) { return x * y; }
    },
    DIVIDE("/") {
        public double apply(double x, double y) { return x / y; }
    };

    private final String symbol;

    Operation(String symbol) { this.symbol = symbol; }

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

    public abstract double apply(double x, double y);

    // μ½”λ“œ 34-7 μ—΄κ±° νƒ€μž…μš© fromString λ©”μ„œλ“œ κ΅¬ν˜„ν•˜κΈ° (216μͺ½)
    private static final Map<String, Operation> stringToEnum =
            Stream.of(values()).collect(
                    toMap(Object::toString, e -> e));

    // μ§€μ •ν•œ λ¬Έμžμ—΄μ— ν•΄λ‹Ήν•˜λŠ” Operation을 (μ‘΄μž¬ν•œλ‹€λ©΄) λ°˜ν™˜ν•œλ‹€.
    public static Optional<Operation> fromString(String symbol) {
        return Optional.ofNullable(stringToEnum.get(symbol));
    }

    public static void main(String[] args) {
        double x = Double.parseDouble(args[0]);
        double y = Double.parseDouble(args[1]);
        for (Operation op : Operation.values())
            System.out.printf("%f %s %f = %f%n",
                    x, op, y, op.apply(x, y));
    }
}
  • μ „λž΅ μ—΄κ±° νƒ€μž… νŒ¨ν„΄
    • PayrollDay μ—΄κ±° νƒ€μž…μ˜ μƒμ„±μžμ—μ„œ μ μ ˆν•œ μž”μ—…μˆ˜λ‹Ή μ „λž΅(PayType)을 선택
    • PayrollDay μ—΄κ±° νƒ€μž…μ€ μž”μ—…μˆ˜λ‹Ή 계산을 κ·Έ μ „λž΅ μ—΄κ±° νŒ¨ν„΄μ— μœ„μž„ν•˜μ—¬, switchλ¬Έμ΄λ‚˜ μƒμˆ˜λ³„ λ©”μ„œλ“œ κ΅¬ν˜„μ—†μ΄ μ•ˆμ „ν•˜κ³  μœ μ—°ν•˜κ²Œ 섀계.
// μ „λž΅ μ—΄κ±° νƒ€μž… νŒ¨ν„΄
enum PayrollDay {
    MONDAY(WEEKDAY), TUESDAY(WEEKDAY), WEDNESDAY(WEEKDAY),
    THURSDAY(WEEKDAY), FRIDAY(WEEKDAY),
    SATURDAY(WEEKEND), SUNDAY(WEEKEND);

    private final PayType payType;

    PayrollDay(PayType payType) { this.payType = payType; }
    
    int pay(int minutesWorked, int payRate) {
        return payType.pay(minutesWorked, payRate);
    }

    // μ „λž΅ μ—΄κ±° νƒ€μž…
    enum PayType {
        WEEKDAY {
            int overtimePay(int minsWorked, int payRate) {
                return minsWorked <= MINS_PER_SHIFT ? 0 :
                        (minsWorked - MINS_PER_SHIFT) * payRate / 2;
            }
        },
        WEEKEND {
            int overtimePay(int minsWorked, int payRate) {
                return minsWorked * payRate / 2;
            }
        };

        abstract int overtimePay(int mins, int payRate);
        private static final int MINS_PER_SHIFT = 8 * 60;

        int pay(int minsWorked, int payRate) {
            int basePay = minsWorked * payRate;
            return basePay + overtimePay(minsWorked, payRate);
        }
    }

    public static void main(String[] args) {
        for (PayrollDay day : values())
            System.out.printf("%-10s%d%n", day, day.pay(8 * 60, 1));
    }
}
  • μœ μš©ν•œ μ—΄κ±° νƒ€μž… λ©”μ„œλ“œ
    • values() : μ •μ˜λœ μƒμˆ˜λ“€μ˜ 값을 배열에 λ‹΄μ•„ λ°˜ν™˜.
    • valueOf(String) : μƒμˆ˜ 이름을 λ¬Έμžμ—΄λ‘œ μž…λ ₯λ°›μ•„ κ·Έ 이름에 ν•΄λ‹Ήν•˜λŠ” μƒμˆ˜λ₯Ό λ°˜ν™˜
  • 정리
    • ν•„μš”ν•œ μ›μ†Œλ₯Ό μ»΄νŒŒμΌνƒ€μž„μ— μ•Œ 수 μžˆλŠ” μƒμˆ˜ 집합이라면 항상 μ—΄κ±° νƒ€μž…μ„ μ‚¬μš©ν•˜μž.
    • μ—΄κ±° νƒ€μž…μ˜ μ–΄λ–€ λ©”μ„œλ“œκ°€ μƒμˆ˜λ³„λ‘œ λ‹€λ₯΄κ²Œ λ™μž‘ν•΄μ•Όν•  경우
      • switchλ¬Έ λŒ€μ‹  μƒμˆ˜λ³„ λ©”μ„œλ“œ κ΅¬ν˜„ μ‚¬μš©ν•˜κΈ°
    • μ—΄κ±° νƒ€μž…μ˜ μƒμˆ˜ 일뢀가 같은 λ™μž‘μ„ κ³΅μœ ν•œλ‹€λ©΄?
      • μ „λž΅ μ—΄κ±° νƒ€μž… νŒ¨ν„΄ μ‚¬μš©ν•˜κΈ°


πŸ’‘ ordinal λ©”μ„œλ“œ λŒ€μ‹  μΈμŠ€ν„΄μŠ€ ν•„λ“œλ₯Ό μ‚¬μš©ν•˜λΌ

β€œμ—΄κ±° νƒ€μž… μƒμˆ˜μ— μ—°κ²°λœ 값은 ordinalλ©”μ„œλ“œλ‘œ 얻지 말고, μΈμŠ€ν„΄μŠ€ ν•„λ“œμ— μ €μž₯ν•˜μžβ€

1. ordinal λ©”μ„œλ“œ

  • ordinal() : ν•΄λ‹Ή μƒμˆ˜κ°€ κ·Έ μ—΄κ±° νƒ€μž…μ—μ„œ λͺ‡ 번째 μœ„μΉ˜μΈμ§€λ₯Ό λ°˜ν™˜
  • ordinal을 잘λͺ» μ‚¬μš©ν•œ μ˜ˆμ‹œ
    • μœ μ§€λ³΄μˆ˜ν•˜κΈ° λ”μ°ν•œ μ½”λ“œλ‹€..
    • μƒμˆ˜ 선언을 λ°”κΎΈλŠ” μˆœκ°„ numberOfMusiciansκ°€ μ˜€λ™μž‘ν•˜λ©°, 이미 μ‚¬μš© 쀑인 μ •μˆ˜μ™€ 값이 같은 μƒμˆ˜λŠ” μΆ”κ°€ν•  방법이 μ—†μŒ.
      • ex) 8쀑주가 이미 μžˆμœΌλ‹ˆ λ˜‘κ°™μ΄ 8λͺ…이 μ—°μ£Όν•˜λŠ” 볡4μ€‘μ£ΌλŠ” μΆ”κ°€ν•  수 μ—†μŒ
public enum Ensemble {
		SOLO, DUET, TRIO, QUARTET, QUINTET,
		SEXTET, SEPTET, OCTET, NONET, DECTET;

		public int numberOfMusicians() { return ordinal() + 1; }
}

2. μΈμŠ€ν„΄μŠ€ ν•„λ“œ

β†’ μΈμŠ€ν„΄μŠ€ ν•„λ“œμ— μ €μž₯ν•˜λ©΄ μœ„μ™€ 같은 λ¬Έμ œλ“€μ΄ λ§λ”νžˆ 해결됨

  • μΈμŠ€ν„΄μŠ€ ν•„λ“œλ₯Ό μ‚¬μš©ν•œ 예
// μΈμŠ€ν„΄μŠ€ ν•„λ“œμ— μ •μˆ˜ 데이터λ₯Ό μ €μž₯ν•˜λŠ” μ—΄κ±° νƒ€μž…
public enum Ensemble {
    SOLO(1), DUET(2), TRIO(3), QUARTET(4), QUINTET(5),
    SEXTET(6), SEPTET(7), OCTET(8), DOUBLE_QUARTET(8),
    NONET(9), DECTET(10), TRIPLE_QUARTET(12);

    private final int numberOfMusicians;
    Ensemble(int size) { this.numberOfMusicians = size; }
    public int numberOfMusicians() { return numberOfMusicians; }
}


πŸ’‘ λΉ„νŠΈ ν•„λ“œ λŒ€μ‹  EnumSet을 μ‚¬μš©ν•˜λΌ

β€œEnumSet 클래슀 : λΉ„νŠΈ ν•„λ“œ μˆ˜μ€€μ˜ λͺ…λ£Œν•¨κ³Ό μ„±λŠ₯ + μ—΄κ±° νƒ€μž…μ˜ μž₯점”

1. λΉ„νŠΈ ν•„λ“œ

  • λΉ„νŠΈ ν•„λ“œ μ—΄κ±° μƒμˆ˜ μ˜ˆμ‹œ
    • λΉ„νŠΈ ν•„λ“œ(bit field) : λΉ„νŠΈλ³„ OR을 μ‚¬μš©ν•΄ μ—¬λŸ¬ μƒμˆ˜λ₯Ό ν•˜λ‚˜μ˜ μ§‘ν•©μœΌλ‘œ λͺ¨μ€ 것.
    • text.applyStyles(STYLE_BOLD | STYLE_ITALIC); 처럼 μ‚¬μš©.
public class Text {
		public static final int STYLE_BOLD = 1 << 0; // 1
		public static final int STYLE_ITALIC = 1 << 1; // 2
		public static final int STYLE_UNDERLINE = 1 << 2; // 4
		public static final int STYLE_STRIKETHROUGH = 1 << 3; // 8		
		
		// λ§€κ°œλ³€μˆ˜ stylesλŠ” 0개 μ΄μƒμ˜ STYLE_ μƒμˆ˜λ₯Ό λΉ„νŠΈλ³„ ORν•œ 값이닀.
		public void applyStyles(int styles) { ... }
}
  • λΉ„νŠΈ ν•„λ“œμ˜ 단점
    1. μ •μˆ˜ μ—΄κ±° μƒμˆ˜μ˜ 단점을 κ·ΈλŒ€λ‘œ μ§€λ‹˜
    2. λΉ„νŠΈ ν•„λ“œ 값이 κ·ΈλŒ€λ‘œ 좜λ ₯되면 λ‹¨μˆœν•œ μ •μˆ˜ μ—΄κ±° μƒμˆ˜λ₯Ό 좜λ ₯ν•  λ•Œλ³΄λ‹€ ν•΄μ„ν•˜κΈ°κ°€ 훨씬 μ–΄λ ΅λ‹€.
      • μ–΄λ–€ μ‘°ν•©μœΌλ‘œ λΉ„νŠΈ ν•„λ“œ 값이 λ‚˜μ™”λŠ”μ§€λ₯Ό μ•Œμ•„λ‚΄μ•Όν•˜κΈ° λ•Œλ¬Έ.
    3. μ΅œλŒ€ λͺ‡ λΉ„νŠΈκ°€ ν•„μš”ν•œμ§€λ₯Ό APIμž‘μ„± μ‹œ 미리 μ˜ˆμΈ‘ν•˜μ—¬ μ μ ˆν•œ νƒ€μž…(int or long)을 선택해야 함.

2. EnumSet

β†’ μ—΄κ±° νƒ€μž… μƒμˆ˜μ˜ κ°’μœΌλ‘œ κ΅¬μ„±λœ 집합을 효과적으둜 ν‘œν˜„ν•΄μ£ΌλŠ” EnumSet을 μ‚¬μš©ν•˜μž.

  • EnumSet μ‚¬μš© μ˜ˆμ‹œ
// EnumSet - λΉ„νŠΈ ν•„λ“œλ₯Ό λŒ€μ²΄ν•˜λŠ” ν˜„λŒ€μ  기법
public class Text {
    public enum Style {BOLD, ITALIC, UNDERLINE, STRIKETHROUGH}

    // μ–΄λ–€ Set을 λ„˜κ²¨λ„ λ˜λ‚˜, EnumSet이 κ°€μž₯ μ’‹λ‹€.
    public void applyStyles(Set<Style> styles) {
        System.out.printf("Applying styles %s to text%n",
                Objects.requireNonNull(styles));
    }

    // μ‚¬μš© 예
    public static void main(String[] args) {
        Text text = new Text();
        text.applyStyles(EnumSet.of(Style.BOLD, Style.ITALIC));
    }
}
  • EnumSet
    1. Set μΈν„°νŽ˜μ΄μŠ€λ₯Ό μ™„λ²½νžˆ κ΅¬ν˜„ν•˜λ©°, νƒ€μž… μ•ˆμ „
    2. λ‚΄λΆ€λŠ” λΉ„νŠΈ λ²‘ν„°λ‘œ κ΅¬ν˜„λ˜μ–΄ μžˆμ–΄, λŒ€λΆ€λΆ„μ˜ 경우 λΉ„νŠΈ ν•„λ“œμ— λΉ„κ²¬λ˜λŠ” μ„±λŠ₯을 λ³΄μ—¬μ€Œ
    3. removeAllκ³Ό retainAllκ³Ό 같은 λŒ€λŸ‰ μž‘μ—…μ€ λΉ„νŠΈλ₯Ό 효율적으둜 μ²˜λ¦¬ν•  수 μžˆλŠ” μ‚°μˆ  연산을 μ¨μ„œ κ΅¬ν˜„ν•˜μ˜€μŒ


πŸ’‘ ordinal 인덱싱 λŒ€μ‹  EnumMap을 μ‚¬μš©ν•˜λΌ

β€œλ°°μ—΄μ˜ 인덱슀λ₯Ό μ–»κΈ° μœ„ν•΄ ordinal을 μ“°λŠ” 것은 일반적으둜 쒋지 μ•ŠμœΌλ‹ˆ, λŒ€μ‹  EnumMap을 μ‚¬μš©ν•˜λΌβ€

  • Plant 클래슀
// 식물을 μ•„μ£Ό λ‹¨μˆœν•˜κ²Œ ν‘œν˜„ν•œ 클래슀 (226μͺ½)
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;
    }
}

1. ordinal 인덱싱

  • ordinal()을 λ°°μ—΄ 인덱슀둜 μ‚¬μš©ν•˜λŠ” μ˜ˆμ‹œ
// ordinal()을 λ°°μ—΄ 인덱슀둜 μ‚¬μš© - 따라 ν•˜μ§€ 말 것!
Set<Plant>[] plantsByLifeCycleArr =
        (Set<Plant>[]) new Set[Plant.LifeCycle.values().length];
for (int i = 0; i < plantsByLifeCycleArr.length; i++)
    plantsByLifeCycleArr[i] = new HashSet<>();
for (Plant p : garden)
    plantsByLifeCycleArr[p.lifeCycle.ordinal()].add(p);
// κ²°κ³Ό 좜λ ₯
for (int i = 0; i < plantsByLifeCycleArr.length; i++) {
    System.out.printf("%s: %s%n",
            Plant.LifeCycle.values()[i], plantsByLifeCycleArr[i]);
}
  • 문제점
    1. 배열은 μ œλ„€λ¦­κ³Ό ν˜Έν™˜λ˜μ§€ μ•ŠμœΌλ‹ˆ 비검사 ν˜•λ³€ν™˜μ„ μˆ˜ν–‰ν•΄μ•Ό ν•˜κ³  κΉ”λ”νžˆ μ»΄νŒŒμΌλ˜μ§€ μ•Šμ„ κ²ƒμž„.
    2. 배열은 각 인덱슀의 의미λ₯Ό λͺ¨λ₯΄λ‹ˆ 좜λ ₯ 결과에 직접 λ ˆμ΄λΈ”μ„ 달아야 함.
    3. μ •ν™•ν•œ μ •μˆ«κ°’μ„ μ‚¬μš©ν•œλ‹€λŠ” 것을 직접 보증해야 함. (μ •μˆ˜λŠ” μ—΄κ±° νƒ€μž…κ³Ό 달리 νƒ€μž… μ•ˆμ „ν•˜μ§€ μ•ŠκΈ° λ•Œλ¬Έ)
      • 잘λͺ»λœ 값을 μ‚¬μš©ν•˜λ©΄ 잘λͺ»λœ λ™μž‘μ„ 묡묡히 μˆ˜ν–‰ν•˜κ±°λ‚˜ (운이 μ’‹λ‹€λ©΄)ArrayIndexOutOfBoundsException을 던질 κ²ƒμž„.

2. EnumMap

  • EnumMap을 μ‚¬μš©ν•˜λŠ” μ˜ˆμ‹œ
Map<Plant.LifeCycle, Set<Plant>> plantsByLifeCycle =
        new EnumMap<>(Plant.LifeCycle.class);
for (Plant.LifeCycle lc : Plant.LifeCycle.values())
    plantsByLifeCycle.put(lc, new HashSet<>());
for (Plant p : garden)
    plantsByLifeCycle.get(p.lifeCycle).add(p);
System.out.println(plantsByLifeCycle);
  • μž₯점
    1. 더 짧고 λͺ…λ£Œν•˜λ©° μ•ˆμ „ν•˜κ³  μ„±λŠ₯도 ordinal()인덱싱 버전과 동일함.
      • EnumMap λ‚΄λΆ€μ—μ„œ 배열을 μ‚¬μš©ν•˜κΈ° λ•Œλ¬Έμ— μ„±λŠ₯이 동일함.
    2. μ•ˆμ „ν•˜μ§€ μ•Šμ€ ν˜•λ³€ν™˜μ€ 쓰지 μ•Šκ³ , 맡의 킀인 μ—΄κ±° νƒ€μž…μ΄ κ·Έ 자체둜 좜λ ₯용 λ¬Έμžμ—΄μ„ μ œκ³΅ν•˜λ‹ˆ 좜λ ₯ 결과에 직접 λ ˆμ΄λΈ”μ„ 달 일도 μ—†μŒ.
    3. λ°°μ—΄ 인덱슀λ₯Ό κ³„μ‚°ν•˜λŠ” κ³Όμ •μ—μ„œ 였λ₯˜κ°€ λ‚  κ°€λŠ₯성도 μ›μ²œλ΄‰μ‡„λ¨.
  • 닀차원 관계 : EnumMap<..., EnumMap<..>>으둜 ν‘œν˜„ν•΄μ„œ μ‚¬μš©.
    // 쀑첩 EnumMap으둜 데이터와 μ—΄κ±° νƒ€μž… μŒμ„ μ—°κ²°ν–ˆλ‹€
    public enum Phase {
        SOLID, LIQUID, GAS;
        public enum Transition {
            MELT(SOLID, LIQUID), FREEZE(LIQUID, SOLID),
            BOIL(LIQUID, GAS), CONDENSE(GAS, LIQUID),
            SUBLIME(SOLID, GAS), DEPOSIT(GAS, SOLID);
    
            private final Phase from;
            private final Phase to;
            Transition(Phase from, Phase to) {
                this.from = from;
                this.to = to;
            }
    
            // 상전이 맡을 μ΄ˆκΈ°ν™”ν•œλ‹€.
            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))));
            
            public static Transition from(Phase from, Phase to) {
                return m.get(from).get(to);
            }
        }
    
        // κ°„λ‹¨ν•œ 데λͺ¨ ν”„λ‘œκ·Έλž¨ - κΉ”λ”ν•˜μ§€ λͺ»ν•œ ν‘œλ₯Ό 좜λ ₯ν•œλ‹€.
        public static void main(String[] args) {
            for (Phase src : Phase.values()) {
                for (Phase dst : Phase.values()) {
                    Transition transition = Transition.from(src, dst);
                    if (transition != null)
                        System.out.printf("%sμ—μ„œ %s둜 : %s %n", src, dst, transition);
                }
            }
        }
    }


πŸ’‘ ν™•μž₯ν•  수 μžˆλŠ” μ—΄κ±° νƒ€μž…μ΄ ν•„μš”ν•˜λ©΄ μΈν„°νŽ˜μ΄μŠ€λ₯Ό μ‚¬μš©ν•˜λΌ

β€œμ—΄κ±° νƒ€μž… μžμ²΄λŠ” ν™•μž₯ν•  수 μ—†μ§€λ§Œ, μΈν„°νŽ˜μ΄μŠ€μ™€ κ·Έ μΈν„°νŽ˜μ΄μŠ€λ₯Ό κ΅¬ν˜„ν•˜λŠ” κΈ°λ³Έ μ—΄κ±° νƒ€μž…μ„ μ‚¬μš©ν•΄ 같은 효과λ₯Ό λ‚Ό 수 μžˆμŒβ€

1. μ—΄κ±° νƒ€μž… ν™•μž₯

  • μ—΄κ±° νƒ€μž…μ€ ν™•μž₯ν•  수 μ—†μŒ.
  • 사싀 λŒ€λΆ€λΆ„ μƒν™©μ—μ„œ μ—΄κ±° νƒ€μž…μ„ ν™•μž₯ν•˜λŠ” 건 쒋지 μ•Šμ€ μƒκ°μž„
    • ν™•μž₯ν•œ νƒ€μž… μ›μ†ŒλŠ” 기반 νƒ€μž…μ˜ μ›μ†Œλ‘œ μ·¨κΈ‰ν•˜μ§€λ§Œ κ·Έ λ°˜λŒ€λŠ” μ„±λ¦½ν•˜μ§€ μ•ŠλŠ”λ‹€λ©΄ μ΄μƒν•˜κΈ° λ•Œλ¬Έ
    • 기반 νƒ€μž…κ³Ό ν™•μž₯된 νƒ€μž…λ“€μ˜ μ›μ†Œ λͺ¨λ‘λ₯Ό μˆœνšŒν•  방법도 λ§ˆλ•…μΉ˜ μ•ŠμŒ.

2. μΈν„°νŽ˜μ΄μŠ€ κ΅¬ν˜„ (ν™•μž₯ 흉내 λ‚΄κΈ°)

  • κΈ°λ³Έ 아이디어 : μ—΄κ±° νƒ€μž…μ΄ μž„μ˜μ˜ μΈν„°νŽ˜μ΄μŠ€λ₯Ό κ΅¬ν˜„ν•  수 μžˆλ‹€λŠ” 사싀 이용
  • μ—°μ‚° μ½”λ“œμš© μΈν„°νŽ˜μ΄μŠ€λ₯Ό μ •μ˜ν•˜κ³  μ—΄κ±° νƒ€μž…μ΄ μΈν„°νŽ˜μ΄μŠ€λ₯Ό κ΅¬ν˜„ν•œ 예
public interface Operation {
    double apply(double x, double y);
}

public enum ExtendedOperation implements Operation {
    EXP("^") {
        public double apply(double x, double y) {
            return Math.pow(x, y);
        }
    },
    REMAINDER("%") {
        public double apply(double x, double y) {
            return x % y;
        }
    };
    private final String symbol;
    ExtendedOperation(String symbol) {
        this.symbol = symbol;
    }
    @Override public String toString() {
        return symbol;
    }

    // μ»¬λ ‰μ…˜ μΈμŠ€ν„΄μŠ€λ₯Ό μ΄μš©ν•΄ ν™•μž₯된 μ—΄κ±° νƒ€μž…μ˜ λͺ¨λ“  μ›μ†Œλ₯Ό μ‚¬μš©ν•˜λŠ” 예 (235μͺ½)
    public static void main(String[] args) {
        double x = Double.parseDouble(args[0]);
        double y = Double.parseDouble(args[1]);
        test(Arrays.asList(ExtendedOperation.values()), x, y);
    }
    private static void test(Collection<? extends Operation> opSet,
                             double x, double y) {
        for (Operation op : opSet)
            System.out.printf("%f %s %f = %f%n",
                    x, op, y, op.apply(x, y));
    }
}
  • μž₯점 : APIκ°€ κΈ°λ³Έ μ—΄κ±° νƒ€μž…μ„ 직접 λͺ…μ‹œν•˜μ§€ μ•Šκ³  μΈν„°νŽ˜μ΄μŠ€ 기반으둜 μž‘μ„±λ˜μ—ˆλ‹€λ©΄ κΈ°λ³Έ μ—΄κ±° νƒ€μž… μΈμŠ€ν„΄μŠ€κ°€ μ“°μ΄λŠ” λͺ¨λ“  곳을 μƒˆλ‘œ ν™•μž₯ν•œ μ—΄κ±° νƒ€μž…μ˜ μΈμŠ€ν„΄μŠ€λ‘œ λŒ€μ²΄ν•΄ μ‚¬μš©ν•  수 있음
    • ex) μœ„ μ½”λ“œμ—μ„œ for (Operation op : opSet)처럼.
  • ν•œκ³„ : μ—΄κ±° νƒ€μž…λΌλ¦¬ κ΅¬ν˜„ 상속 λΆˆκ°€.


πŸ’‘ λͺ…λͺ… νŒ¨ν„΄λ³΄λ‹€ μ• λ„ˆν…Œμ΄μ…˜μ„ μ‚¬μš©ν•˜λΌ

β€œμ–΄λ…Έν…Œμ΄μ…˜μœΌλ‘œ ν•  수 μžˆλŠ” 일을 λͺ…λͺ… νŒ¨ν„΄μœΌλ‘œ μ²˜λ¦¬ν•  μ΄μœ κ°€ 없닀”

1. λͺ…λͺ… νŒ¨ν„΄

  • λͺ…λͺ… νŒ¨ν„΄ : λ³€μˆ˜λ‚˜ ν•¨μˆ˜μ˜ 이름을 μΌκ΄€λœ λ°©μ‹μœΌλ‘œ μž‘μ„±ν•˜λŠ”Β νŒ¨ν„΄
  • ex) JUnit은 버전 3κΉŒμ§€ ν…ŒμŠ€νŠΈ λ©”μ„œλ“œ 이름을 test둜 μ‹œμž‘ν•˜κ²Œλ” ν–ˆμŒ.
  • λͺ…λͺ… νŒ¨ν„΄μ˜ 문제점
    1. μ˜€νƒ€κ°€ λ‚˜λ©΄ μ•ˆ 됨
      • ex) μ‹€μˆ˜λ‘œ λ©”μ„œλ“œ 이름을 tsetSafetyOverride둜 μ§€μœΌλ©΄ JUnit3은 이 λ©”μ„œλ“œλ₯Ό λ¬΄μ‹œν•˜κ³  μ§€λ‚˜μΉ¨
    2. μ˜¬λ°”λ₯Έ ν”„λ‘œκ·Έλž¨ μš”μ†Œμ—μ„œλ§Œ μ‚¬μš©λ˜λ¦¬λΌ 보증할 방법이 μ—†μŒ
      • ex) 클래슀 이름을 TestSafetyMechanisms둜 지어 JUnit에 λ˜μ Έμ€¬λ‹€κ³  ν•΄λ³΄μž. κ°œλ°œμžλŠ” 이 ν΄λž˜μŠ€μ— μ •μ˜λœ ν…ŒμŠ€νŠΈ λ©”μ„œλ“œλ“€μ„ μˆ˜ν–‰ν•΄μ£ΌκΈΈ κΈ°λŒ€ν•˜κ² μ§€λ§Œ JUnit은 클래슀 μ΄λ¦„μ—λŠ” 관심이 μ—†μŒ
    3. ν”„λ‘œκ·Έλž¨ μš”μ†Œλ₯Ό λ§€κ°œλ³€μˆ˜λ‘œ 전달할 λ§ˆλ•…ν•œ 방법이 μ—†μŒ.
  • μ–΄λ…Έν…Œμ΄μ…˜μ€ λͺ…λͺ… νŒ¨ν„΄μ˜ λͺ¨λ“  λ¬Έμ œμ μ„ ν•΄κ²°ν•΄μ£ΌλŠ” κ°œλ…μœΌλ‘œ, JUnit도 버전 4λΆ€ν„° μ „λ©΄ λ„μž…ν•˜μ˜€μŒ.

2. 마컀 μ–΄λ…Έν…Œμ΄μ…˜

  • 마컀 μ–΄λ…Έν…Œμ΄μ…˜ : 아무 λ§€κ°œλ³€μˆ˜ 없이 λ‹¨μˆœνžˆ λŒ€μƒμ— λ§ˆν‚Ή(marking)ν•˜λŠ” μ–΄λ…Έν…Œμ΄μ…˜
  • 메타 μ–΄λ…Έν…Œμ΄μ…˜ : μ–΄λ…Έν…Œμ΄μ…˜ 선언에 λ‹€λŠ” μ–΄λ…Έν…Œμ΄μ…˜
    • @Retention(RetentionPolicy.RUNTIME) : μ–΄λ…Έν…Œμ΄μ…˜μ΄ λŸ°νƒ€μž„μ—λ„ μœ μ§€λ˜μ–΄μ•Ό ν•œλ‹€λŠ” ν‘œμ‹œ
    • @Target(ElementType.METHOD) : μ–΄λ…Έν…Œμ΄μ…˜μ΄ λ©”μ„œλ“œ μ„ μ–Έμ—μ„œλ§Œ μ‚¬μš©λ˜μ–΄μ•Ό ν•œλ‹€λŠ” ν‘œμ‹œ
  • 마컀 μ–΄λ…Έν…Œμ΄μ…˜ μ„ μ–Έ μ˜ˆμ‹œ
/**
 * ν…ŒμŠ€νŠΈ λ©”μ„œλ“œμž„μ„ μ„ μ–Έν•˜λŠ” μ• λ„ˆν…Œμ΄μ…˜μ΄λ‹€.
 * λ§€κ°œλ³€μˆ˜ μ—†λŠ” 정적 λ©”μ„œλ“œ μ „μš©μ΄λ‹€.
 */
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface Test {
}
  • 마컀 μ–΄λ…Έν…Œμ΄μ…˜ μ‚¬μš© μ˜ˆμ‹œ
    • Test μ–΄λ…Έν…Œμ΄μ…˜μ— μ£Όμ„μœΌλ‘œ β€œλ§€κ°œλ³€μˆ˜ μ—†λŠ” 정적 λ©”μ„œλ“œ μ „μš©μ΄λ‹€.”라고 μ“°μ—¬μžˆμ§€λ§Œ, ν•΄λ‹Ή 주석을 μ»΄νŒŒμΌλŸ¬κ°€ ν•΄μ„ν•΄μ„œ κ°•μ œν•  μˆ˜λŠ” μ—†μŒ
    • κ·Έλž˜μ„œ μ•„λž˜ μ˜ˆμ‹œλ₯Ό μ›ν•˜λŠ” λŒ€λ‘œ λ™μž‘μ‹œν‚€κΈ° μœ„ν•΄μ„œλŠ” μ μ ˆν•œ μ–΄λ…Έν…Œμ΄μ…˜ μ²˜λ¦¬κΈ°κ°€ ν•„μš”ν•¨
      • κ΄€λ ¨ 방법은 javax.annotation.processing API λ¬Έμ„œ μ°Έκ³ .
// 마컀 μ• λ„ˆν…Œμ΄μ…˜μ„ μ‚¬μš©ν•œ ν”„λ‘œκ·Έλž¨ 예
public class Sample {
    @Test
    public static void m1() { }        // 성곡해야 ν•œλ‹€.
    public static void m2() { }
    @Test public static void m3() {    // μ‹€νŒ¨ν•΄μ•Ό ν•œλ‹€.
        throw new RuntimeException("μ‹€νŒ¨");
    }
    public static void m4() { }  // ν…ŒμŠ€νŠΈκ°€ μ•„λ‹ˆλ‹€.
    @Test public void m5() { }   // 잘λͺ» μ‚¬μš©ν•œ 예: 정적 λ©”μ„œλ“œκ°€ μ•„λ‹ˆλ‹€.
    public static void m6() { }
    @Test public static void m7() {    // μ‹€νŒ¨ν•΄μ•Ό ν•œλ‹€.
        throw new RuntimeException("μ‹€νŒ¨");
    }
    public static void m8() { }
}

3. μ–΄λ…Έν…Œμ΄μ…˜ with λ§€κ°œλ³€μˆ˜

  • μ–΄λ…Έν…Œμ΄μ…˜μ— λ§€κ°œλ³€μˆ˜λ₯Ό μ‚¬μš©ν•˜λŠ” 법을 μ•Œμ•„λ³΄μž
  • λ§€κ°œλ³€μˆ˜ ν•˜λ‚˜λ₯Ό λ°›λŠ” μ–΄λ…Έν…Œμ΄μ…˜ μ„ μ–Έ μ˜ˆμ‹œ
    • Class<? extends Throwable> : Throwable을 ν™•μž₯ν•œ 클래슀의 Class 객체.
/**
 * λͺ…μ‹œν•œ μ˜ˆμ™Έλ₯Ό λ˜μ Έμ•Όλ§Œ μ„±κ³΅ν•˜λŠ” ν…ŒμŠ€νŠΈ λ©”μ„œλ“œμš© μ• λ„ˆν…Œμ΄μ…˜
 */
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface ExceptionTest {
    Class<? extends Throwable> value();
}
  • λ§€κ°œλ³€μˆ˜ ν•˜λ‚˜λ₯Ό λ°›λŠ” μ–΄λ…Έν…Œμ΄μ…˜ μ‚¬μš© μ˜ˆμ‹œ
// λ§€κ°œλ³€μˆ˜ ν•˜λ‚˜μ§œλ¦¬ μ• λ„ˆν…Œμ΄μ…˜μ„ μ‚¬μš©ν•œ ν”„λ‘œκ·Έλž¨
public class Sample2 {
    @ExceptionTest(ArithmeticException.class)
    public static void m1() {  // 성곡해야 ν•œλ‹€.
        int i = 0;
        i = i / i;
    }
    @ExceptionTest(ArithmeticException.class)
    public static void m2() {  // μ‹€νŒ¨ν•΄μ•Ό ν•œλ‹€. (λ‹€λ₯Έ μ˜ˆμ™Έ λ°œμƒ)
        int[] a = new int[0];
        int i = a[1];
    }
    @ExceptionTest(ArithmeticException.class)
    public static void m3() { }  // μ‹€νŒ¨ν•΄μ•Ό ν•œλ‹€. (μ˜ˆμ™Έκ°€ λ°œμƒν•˜μ§€ μ•ŠμŒ)
}
  • λ°°μ—΄ λ§€κ°œλ³€μˆ˜λ₯Ό λ°›λŠ” μ–΄λ…Έν…Œμ΄μ…˜ μ„ μ–Έ μ˜ˆμ‹œ
// λ°°μ—΄ λ§€κ°œλ³€μˆ˜λ₯Ό λ°›λŠ” μ• λ„ˆν…Œμ΄μ…˜ νƒ€μž…
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface ExceptionTest {
    Class<? extends Exception>[] value();
}
  • λ°°μ—΄ λ§€κ°œλ³€μˆ˜λ₯Ό λ°›λŠ” μ–΄λ…Έν…Œμ΄μ…˜ μ‚¬μš© μ˜ˆμ‹œ
// λ°°μ—΄ λ§€κ°œλ³€μˆ˜λ₯Ό λ°›λŠ” μ• λ„ˆν…Œμ΄μ…˜μ„ μ‚¬μš©ν•˜λŠ” ν”„λ‘œκ·Έλž¨
public class Sample3 {
    // 이 λ³€ν˜•μ€ μ›μ†Œ ν•˜λ‚˜μ§œλ¦¬ λ§€κ°œλ³€μˆ˜λ₯Ό λ°›λŠ” μ• λ„ˆν…Œμ΄μ…˜λ„ μ²˜λ¦¬ν•  수 μžˆλ‹€
    @ExceptionTest(ArithmeticException.class)
    public static void m1() {  // 성곡해야 ν•œλ‹€.
        int i = 0;
        i = i / i;
    }
    @ExceptionTest(ArithmeticException.class)
    public static void m2() {  // μ‹€νŒ¨ν•΄μ•Ό ν•œλ‹€. (λ‹€λ₯Έ μ˜ˆμ™Έ λ°œμƒ)
        int[] a = new int[0];
        int i = a[1];
    }
    @ExceptionTest(ArithmeticException.class)
    public static void m3() { }  // μ‹€νŒ¨ν•΄μ•Ό ν•œλ‹€. (μ˜ˆμ™Έκ°€ λ°œμƒν•˜μ§€ μ•ŠμŒ)

    // λ°°μ—΄ λ§€κ°œλ³€μˆ˜λ₯Ό λ°›λŠ” μ• λ„ˆν…Œμ΄μ…˜μ„ μ‚¬μš©ν•˜λŠ” μ½”λ“œ
    @ExceptionTest({ IndexOutOfBoundsException.class,
                     NullPointerException.class })
    public static void doublyBad() {   // 성곡해야 ν•œλ‹€.
        List<String> list = new ArrayList<>();

        // μžλ°” API λͺ…세에 λ”°λ₯΄λ©΄ λ‹€μŒ λ©”μ„œλ“œλŠ” IndexOutOfBoundsExceptionμ΄λ‚˜
        // NullPointerException을 던질 수 μžˆλ‹€.
        list.addAll(5, null);
    }
}

4. λ°˜λ³΅κ°€λŠ₯ μ–΄λ…Έν…Œμ΄μ…˜

  • ν•˜λ‚˜μ˜ ν”„λ‘œκ·Έλž¨ μš”μ†Œμ— 같은 μ–΄λ…Έν…Œμ΄μ…˜μ„ μ—¬λŸ¬ 번 달도둝 λ§Œλ“€κ³  싢은 상황에 μ‚¬μš©
  • 반볡 κ°€λŠ₯ν•œ μ–΄λ…Έν…Œμ΄μ…˜ μ„ μ–Έ μ˜ˆμ‹œ
    • 반볡 κ°€λŠ₯ μ–΄λ…Έν…Œμ΄μ…˜ μ„ μ–Έ 방법 : @Repeatable 메타 μ–΄λ…Έν…Œμ΄μ…˜μ„ 달면 됨
      • 단, @Repeatable μ–΄λ…Έν…Œμ΄μ…˜μ˜ λ§€κ°œλ³€μˆ˜λ‘œ β€˜μ»¨ν…Œμ΄λ„ˆ μ–΄λ…Έν…Œμ΄μ…˜β€™μ„ 전달해야 함.
      • μ»¨ν…Œμ΄λ„ˆ μ–΄λ…Έν…Œμ΄μ…˜ : λ‚΄λΆ€ μ–΄λ…Έν…Œμ΄μ…˜ νƒ€μž…μ˜ 배열을 λ°˜ν™˜ν•˜λŠ” value λ©”μ„œλ“œλ₯Ό μ •μ˜ 해야함
// 반볡 κ°€λŠ₯ν•œ μ• λ„ˆν…Œμ΄μ…˜μ˜ μ»¨ν…Œμ΄λ„ˆ μ• λ„ˆν…Œμ΄μ…˜
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface ExceptionTestContainer {
    ExceptionTest[] value();
}

// 반볡 κ°€λŠ₯ν•œ μ• λ„ˆν…Œμ΄μ…˜ νƒ€μž…
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
@Repeatable(ExceptionTestContainer.class)
public @interface ExceptionTest {
    Class<? extends Throwable> value();
}
  • 반볡 κ°€λŠ₯ν•œ μ–΄λ…Έν…Œμ΄μ…˜ μ‚¬μš© μ˜ˆμ‹œ
// 반볡 κ°€λŠ₯ν•œ μ• λ„ˆν…Œμ΄μ…˜μ„ μ‚¬μš©ν•œ ν”„λ‘œκ·Έλž¨
public class Sample4 {
    // 반볡 κ°€λŠ₯ μ• λ„ˆν…Œμ΄μ…˜μ„ 두 번 단 μ½”λ“œ
    @ExceptionTest(IndexOutOfBoundsException.class)
    @ExceptionTest(NullPointerException.class)
    public static void doublyBad() {
        List<String> list = new ArrayList<>();

        // μžλ°” API λͺ…세에 λ”°λ₯΄λ©΄ λ‹€μŒ λ©”μ„œλ“œλŠ” IndexOutOfBoundsExceptionμ΄λ‚˜
        // NullPointerException을 던질 수 μžˆλ‹€.
        list.addAll(5, null);
    }
}


πŸ’‘ @Override μ–΄λ…Έν…Œμ΄μ…˜μ„ μΌκ΄€λ˜κ²Œ μ‚¬μš©ν•˜λΌ

β€œμƒμœ„ 클래슀의 λ©”μ„œλ“œλ₯Ό μž¬μ •μ˜ν•˜λ €λŠ” λͺ¨λ“  λ©”μ„œλ“œμ— @Override μ–΄λ…Έν…Œμ΄μ…˜μ„ λ‹¬μžβ€

  • μž¬μ •μ˜ν•œ λͺ¨λ“  λ©”μ„œλ“œμ— @Override μ–΄λ…Έν…Œμ΄μ…˜μ„ μ˜μ‹μ μœΌλ‘œ 달면 μ‹€μˆ˜ν–ˆμ„ λ•Œ, μ»΄νŒŒμΌλŸ¬κ°€ 잘 μ•Œλ €μ€„ κ²ƒμž„
  • μ˜ˆμ™Έ κ²½μš°κ°€ ν•œ 가지 있음.
    • ꡬ체 ν΄λž˜μŠ€μ—μ„œ μƒμœ„ 클래슀의 좔상 λ©”μ„œλ“œλ₯Ό μž¬μ •μ˜ν•œ κ²½μš°μ—” 이 μ–΄λ…Έν…Œμ΄μ…˜μ„ 달지 μ•Šμ•„λ„ 됨. 그런데 단닀고 ν•΄μ„œ ν•΄λ‘œμšΈ 것도 μ—†μŒ. β†’ 걍 λ‹¬μž.


πŸ’‘ μ •μ˜ν•˜λ €λŠ” 것이 νƒ€μž…μ΄λΌλ©΄ 마컀 μΈν„°νŽ˜μ΄μŠ€λ₯Ό μ‚¬μš©ν•˜λΌ

β€œλ§ˆμ»€ μΈν„°νŽ˜μ΄μŠ€μ™€ λ§ˆν„° μ–΄λ…Έν…Œμ΄μ…˜μ€ 각자의 μ“°μž„μ΄ μžˆλ‹€.”

1. 마컀 μΈν„°νŽ˜μ΄μŠ€

  • 마컀 μΈν„°νŽ˜μ΄μŠ€ : 아무 λ©”μ„œλ“œλ„ λ‹΄κ³  μžˆμ§€ μ•Šκ³ , 단지 μžμ‹ μ„ κ΅¬ν˜„ν•˜λŠ” ν΄λž˜μŠ€κ°€ νŠΉμ • 속성을 가짐을 ν‘œμ‹œν•΄μ£ΌλŠ” μΈν„°νŽ˜μ΄μŠ€
  • ex) Serializable μΈν„°νŽ˜μ΄μŠ€
  • 마컀 μΈν„°νŽ˜μ΄μŠ€κ°€ 마컀 μ–΄λ…Έν…Œμ΄μ…˜λ³΄λ‹€ λ‚˜μ€ 점
    1. 마컀 μΈν„°νŽ˜μ΄μŠ€λŠ” 이λ₯Ό κ΅¬ν˜„ν•œ 클래슀의 μΈμŠ€ν„΄μŠ€λ“€μ„ κ΅¬λΆ„ν•˜λŠ” νƒ€μž…μœΌλ‘œ μ“Έ 수 μžˆμœΌλ‚˜, 마컀 μ–΄λ…Έν…Œμ΄μ…˜μ€ 그렇지 μ•ŠμŒ.
      • 마컀 μΈν„°νŽ˜μ΄μŠ€λŠ” μ–΄μ—Ών•œ νƒ€μž…μ΄λ―€λ‘œ 마컀 μ–΄λ…Έν…Œμ΄μ…˜μ„ μ‚¬μš©ν–ˆλ‹€λ©΄ λŸ°νƒ€μž„μ—μ•Ό 발견될 였λ₯˜λ₯Ό 컴파일 νƒ€μž„μ— μž‘μ„ 수 있음
    2. 적용 λŒ€μƒμ„ 더 μ •λ°€ν•˜κ²Œ 지정할 수 있음
      • 적용 λŒ€μƒ(@Target)을 ElementType.TYPE으둜 μ„ μ–Έν•œ μ–΄λ…Έν…Œμ΄μ…˜μ€ λͺ¨λ“  νƒ€μž…(클래슀, μΈν„°νŽ˜μ΄μŠ€, μ—΄κ±° νƒ€μž…, μ–΄λ…Έν…Œμ΄μ…˜)에 달 수 있음. λΆ€μ°©ν•  수 μžˆλŠ” νƒ€μž…μ„ μ„Έλ°€νžˆ μ œν•œν•  수 μ—†μŒ.
      • νŠΉμ • μΈν„°νŽ˜μ΄μŠ€λ₯Ό κ΅¬ν˜„ν•œ ν΄λž˜μŠ€μ—λ§Œ μ μš©ν•˜κ³  싢은 λ§ˆμ»€κ°€ μžˆλ‹€λ©΄ κ·Έλƒ₯ λ§ˆν‚Ήν•˜κ³  싢은 ν¬λž˜μŠ€μ—μ„œλ§Œ κ·Έ μΈν„°νŽ˜μ΄μŠ€λ₯Ό κ΅¬ν˜„ν•˜λ©΄ 됨.
  • λ°˜λŒ€λ‘œ, 마컀 μ–΄λ…Έν…Œμ΄μ…˜μ΄ 마컀 μΈν„°νŽ˜μ΄μŠ€λ³΄λ‹€ λ‚˜μ€ 점
    • κ±°λŒ€ν•œ μ–΄λ…Έν…Œμ΄μ…˜ μ‹œμŠ€ν…œμ˜ 지원을 λ°›μŒ

2. 마컀 μ–΄λ…Έν…Œμ΄μ…˜

  • κ·Έλ ‡λ‹€λ©΄ 마컀 μ–΄λ…Έν…Œμ΄μ…˜μ€ μ–Έμ œ μ‚¬μš©ν•΄μ•Ό ν•˜λŠ”κ°€?
    • ν΄λž˜μŠ€μ™€ μΈν„°νŽ˜μ΄μŠ€ μ™Έμ˜ ν”„λ‘œκ·Έλž¨ μš”μ†Œ(λͺ¨λ“ˆ, νŒ¨ν‚€μ§€, ν•„λ“œ, μ§€μ—­λ³€μˆ˜ λ“±)에 λ§ˆν‚Ήν•΄μ•Ό ν•  λ•Œ, μ–΄λ…Έν…Œμ΄μ…˜μ„ μ‚¬μš©
    • μ–΄λ…Έν…Œμ΄μ…˜μ„ ν™œλ°œνžˆ ν™œμš©ν•˜λŠ” ν”„λ ˆμž„μ›Œν¬μ—μ„œ μ‚¬μš©ν•˜λ €λŠ” 마컀일 λ•Œ.
  • β€œμ΄ λ§ˆν‚Ήμ΄ 된 객체λ₯Ό λ§€κ°œλ³€μˆ˜λ‘œ λ°›λŠ” λ©”μ„œλ“œλ₯Ό μž‘μ„±ν•  일이 μžˆμ„κΉŒ?”
    • β€œκ·Έλ ‡λ‹€β€μΌ 경우 β†’ 마컀 μΈν„°νŽ˜μ΄μŠ€λ₯Ό μ‚¬μš©ν•΄μ•Ό 함. μ»΄νŒŒμΌνƒ€μž„ νƒ€μž… μ•ˆμ •μ„±μ„ μœ„ν•΄..
  • λ§Œμ•½ 적용 λŒ€μƒμ΄ Element.TYPE인 마컀 μ–΄λ…Έν…Œμ΄μ…˜μ„ μž‘μ„±ν•˜κ³  μžˆλ‹€λ©΄, 마컀 μΈν„°νŽ˜μ΄μŠ€κ°€ λ‚«μ§€λŠ” μ•Šμ„μ§€ κ³ λ―Όν•΄λ³΄μž.
profile
https://dev-peter.online/

0개의 λŒ“κΈ€