item 39 JungHyunLyoo - JAVA-JIKIMI/EFFECTIVE-JAVA3 GitHub Wiki

λͺ…λͺ… νŒ¨ν„΄μ΄λž€?

λ©”μ†Œλ“œλ‚˜ 클래슀 λ“±μ˜ 이름을 지을 λ•Œ, νŠΉμ •ν•œ κ·œμΉ™μ„ λ„£μ–΄ ν”„λ ˆμž„μ›Œν¬μ—μ„œ μ‚¬μš©λ  수 있게 ν•˜λŠ” νŒ¨ν„΄

λͺ…λͺ… νŒ¨ν„΄μ˜ 단점

  1. μ˜€νƒ€ testMethod(o), tsetMethod(x)
  2. μ˜¬λ°”λ₯Έ ν”„λ‘œκ·Έλž¨ μš”μ†Œμ—μ„œλ§Œ μ‚¬μš©λ˜λ¦¬λΌ 보증할 방법이 μ—†μŒ (λ©”μ†Œλ“œ 이름이 μ•„λ‹Œ 클래슀 이름에 κ·œμΉ™μ„ μ μš©ν•¨)
  3. ν”„λ‘œκ·Έλž¨ μš”μ†Œλ₯Ό λ§€κ°œλ³€μˆ˜λ‘œ 전달할 λ§ˆλ•…ν•œ 방법이 μ—†μŒ

μ• λ„ˆν…Œμ΄μ…˜μ€ 이 λͺ¨λ“  문제λ₯Ό ν•΄κ²°ν•΄μ€€λ‹€!

μ• λ„ˆν…Œμ΄μ…˜ 생성

package effectivejava.chapter6.item39.markerannotation;
import java.lang.annotation.*;

import java.lang.annotation.*;

/**
 * ν…ŒμŠ€νŠΈ λ©”μ„œλ“œμž„μ„ μ„ μ–Έν•˜λŠ” μ• λ„ˆν…Œμ΄μ…˜μ΄λ‹€.
 * λ§€κ°œλ³€μˆ˜ μ—†λŠ” 정적 λ©”μ„œλ“œ μ „μš©μ΄λ‹€.
 */
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD) -> 메타 μ• λ„ˆν…Œμ΄μ…˜
public @interface Test { -> 마컀 μ• λ„ˆν…Œμ΄μ…˜
}

μ• λ„ˆν…Œμ΄μ…˜ μ‚¬μš©

ackage effectivejava.chapter6.item39.markerannotation;

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() { }
}

μ• λ„ˆν…Œμ΄μ…˜μ„ μ‚¬μš©ν•œ 클래슀λ₯Ό μ‚¬μš©

package effectivejava.chapter6.item39.markerannotation;

import java.lang.reflect.*;

public class RunTests {
    public static void main(String[] args) throws Exception {
        int tests = 0;
        int passed = 0;
        Class<?> testClass = Class.forName(args[0]);
        for (Method m : testClass.getDeclaredMethods()) {
            if (m.isAnnotationPresent(Test.class)) {
                tests++;
                try {
                    m.invoke(null);
                    passed++;
                } catch (InvocationTargetException wrappedExc) {
                    Throwable exc = wrappedExc.getCause();
                    System.out.println(m + " μ‹€νŒ¨: " + exc);
                } catch (Exception exc) {
                    System.out.println("잘λͺ» μ‚¬μš©ν•œ @Test: " + m);
                }
            }
        }
        System.out.printf("성곡: %d, μ‹€νŒ¨: %d%n",
                passed, tests - passed);
    }
}

νŒŒλΌλ―Έν„°λ₯Ό 받을 수 μžˆλŠ” μ• λ„ˆν…Œμ΄μ…˜ 생성

package effectivejava.chapter6.item39.annotationwithparameter;

import java.lang.annotation.*;

/**
 * λͺ…μ‹œν•œ μ˜ˆμ™Έλ₯Ό λ˜μ Έμ•Όλ§Œ μ„±κ³΅ν•˜λŠ” ν…ŒμŠ€νŠΈ λ©”μ„œλ“œμš© μ• λ„ˆν…Œμ΄μ…˜
 */
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface ExceptionTest {
    Class<? extends Throwable> value();
}

νŒŒλΌλ―Έν„°λ₯Ό 받을 수 μžˆλŠ” μ• λ„ˆν…Œμ΄μ…˜ μ‚¬μš©

package effectivejava.chapter6.item39.annotationwithparameter;
import effectivejava.chapter6.item39.annotationwithparameter.ExceptionTest;

import java.util.*;

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() { }  // μ‹€νŒ¨ν•΄μ•Ό ν•œλ‹€. (μ˜ˆμ™Έκ°€ λ°œμƒν•˜μ§€ μ•ŠμŒ)
}

νŒŒλΌλ―Έν„°λ₯Ό 받을 수 μžˆλŠ” μ• λ„ˆν…Œμ΄μ…˜μ„ μ‚¬μš©ν•œ 클래슀λ₯Ό μ‚¬μš©

package effectivejava.chapter6.item39.annotationwithparameter;

import effectivejava.chapter6.item39.markerannotation.Test;
import java.lang.reflect.*;

public class RunTests {
    public static void main(String[] args) throws Exception {
        int tests = 0;
        int passed = 0;
        Class<?> testClass = Class.forName(args[0]);
        for (Method m : testClass.getDeclaredMethods()) {
            if (m.isAnnotationPresent(Test.class)) {
                tests++;
                try {
                    m.invoke(null);
                    passed++;
                } catch (InvocationTargetException wrappedExc) {
                    Throwable exc = wrappedExc.getCause();
                    System.out.println(m + " μ‹€νŒ¨: " + exc);
                } catch (Exception exc) {
                    System.out.println("잘λͺ» μ‚¬μš©ν•œ @Test: " + m);
                }
            }

            if (m.isAnnotationPresent(ExceptionTest.class)) {
                tests++;
                try {
                    m.invoke(null);
                    System.out.printf("ν…ŒμŠ€νŠΈ %s μ‹€νŒ¨: μ˜ˆμ™Έλ₯Ό λ˜μ§€μ§€ μ•ŠμŒ%n", m);
                } catch (InvocationTargetException wrappedEx) {
                    Throwable exc = wrappedEx.getCause();
                    Class<? extends Throwable> excType =
                            m.getAnnotation(ExceptionTest.class).value();
                    if (excType.isInstance(exc)) {
                        passed++;
                    } else {
                        System.out.printf(
                                "ν…ŒμŠ€νŠΈ %s μ‹€νŒ¨: κΈ°λŒ€ν•œ μ˜ˆμ™Έ %s, λ°œμƒν•œ μ˜ˆμ™Έ %s%n",
                                m, excType.getName(), exc);
                    }
                } catch (Exception exc) {
                    System.out.println("잘λͺ» μ‚¬μš©ν•œ @ExceptionTest: " + m);
                }
            }
        }

        System.out.printf("성곡: %d, μ‹€νŒ¨: %d%n",
                passed, tests - passed);
    }
}

λ°°μ—΄ νŒŒλΌλ―Έν„°λ₯Ό 받을 수 μžˆλŠ” μ• λ„ˆν…Œμ΄μ…˜ 생성

package effectivejava.chapter6.item39.annotationwitharrayparameter;
import java.lang.annotation.*;

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface ExceptionTest {
    Class<? extends Exception>[] value();
}

λ°°μ—΄ νŒŒλΌλ―Έν„°λ₯Ό 받을 수 μžˆλŠ” μ• λ„ˆν…Œμ΄μ…˜ μ‚¬μš©

package effectivejava.chapter6.item39.annotationwitharrayparameter;

import java.util.*;

public class Sample3 {
    // 이 λ³€ν˜•μ€ μ›μ†Œ ν•˜λ‚˜μ§œλ¦¬ λ§€κ°œλ³€μˆ˜λ₯Ό λ°›λŠ” μ• λ„ˆν…Œμ΄μ…˜λ„ μ²˜λ¦¬ν•  수 μžˆλ‹€. (241μͺ½ 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() { }  // μ‹€νŒ¨ν•΄μ•Ό ν•œλ‹€. (μ˜ˆμ™Έκ°€ λ°œμƒν•˜μ§€ μ•ŠμŒ)

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

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

λ°°μ—΄ νŒŒλΌλ―Έν„°λ₯Ό 받을 수 μžˆλŠ” μ• λ„ˆν…Œμ΄μ…˜μ„ μ‚¬μš©ν•œ 클래슀λ₯Ό μ‚¬μš©

package effectivejava.chapter6.item39.annotationwitharrayparameter;
import effectivejava.chapter6.item39.markerannotation.Test;

import java.lang.reflect.*;

public class RunTests {
    public static void main(String[] args) throws Exception {
        int tests = 0;
        int passed = 0;
        Class<?> testClass = Class.forName(args[0]);
        for (Method m : testClass.getDeclaredMethods()) {
            if (m.isAnnotationPresent(Test.class)) {
                tests++;
                try {
                    m.invoke(null);
                    passed++;
                } catch (InvocationTargetException wrappedExc) {
                    Throwable exc = wrappedExc.getCause();
                    System.out.println(m + " μ‹€νŒ¨: " + exc);
                } catch (Exception exc) {
                    System.out.println("잘λͺ» μ‚¬μš©ν•œ @Test: " + m);
                }
            }

            if (m.isAnnotationPresent(ExceptionTest.class)) {
                tests++;
                try {
                    m.invoke(null);
                    System.out.printf("ν…ŒμŠ€νŠΈ %s μ‹€νŒ¨: μ˜ˆμ™Έλ₯Ό λ˜μ§€μ§€ μ•ŠμŒ%n", m);
                } catch (Throwable wrappedExc) {
                    Throwable exc = wrappedExc.getCause();
                    int oldPassed = passed;
                    Class<? extends Throwable>[] excTypes =
                            m.getAnnotation(ExceptionTest.class).value();
                    for (Class<? extends Throwable> excType : excTypes) {
                        if (excType.isInstance(exc)) {
                            passed++;
                            break;
                        }
                    }
                    if (passed == oldPassed)
                        System.out.printf("ν…ŒμŠ€νŠΈ %s μ‹€νŒ¨: %s %n", m, exc);
                }
            }
        }
        System.out.printf("성곡: %d, μ‹€νŒ¨: %d%n",
                passed, tests - passed);
    }
}

@Repeatable 메타 μ• λ„ˆν…Œμ΄μ…˜?

⚠️ **GitHub.com Fallback** ⚠️