πŸ“˜ μžλ°” κ³ κΈ‰ 문법 μ™„μ „ 정리: ν•¨μˆ˜ν˜• ν”„λ‘œκ·Έλž˜λ° & μ–΄λ…Έν…Œμ΄μ…˜

My Pale Blue DotΒ·2025λ…„ 3μ›” 21일
0

JAVA

λͺ©λ‘ 보기
32/35
post-thumbnail

πŸ“… λ‚ μ§œ

2025-03-21


πŸ“ ν•™μŠ΅ κ°œμš”

μ˜€λŠ˜μ€ μžλ°”μ—μ„œ 자주 μ‚¬μš©λ˜λŠ” ν•¨μˆ˜ν˜• ν”„λ‘œκ·Έλž˜λ°κ³Ό μ–΄λ…Έν…Œμ΄μ…˜(Annotation)을 μ§‘μ€‘μ μœΌλ‘œ ν•™μŠ΅ν–ˆλ‹€.
이 두 μ£Όμ œλŠ” μžλ°”μ˜ μ„ μ–Έν˜• ν”„λ‘œκ·Έλž˜λ°κ³Ό 메타 ν”„λ‘œκ·Έλž˜λ°μ„ κ°€λŠ₯ν•˜κ²Œ ν•˜λŠ” 핡심 문법이닀.
이 ν¬μŠ€νŠΈμ—μ„œλŠ” 각 κ°œλ…μ˜ μ •μ˜λΆ€ν„° μ‹€μ œ μ½”λ“œ 예제, μ‘μš© 및 μ‹€ν–‰ κ²°κ³ΌκΉŒμ§€ μ •λ¦¬ν•œλ‹€.


1️⃣ ν•¨μˆ˜ν˜• ν”„λ‘œκ·Έλž˜λ° in Java

βœ… ν•¨μˆ˜ν˜• ν”„λ‘œκ·Έλž˜λ°μ΄λž€?

  • μƒνƒœ λ³€κ²½ 없이 순수 ν•¨μˆ˜(pure function)λ₯Ό μ΄μš©ν•΄ κ²°κ³Όλ₯Ό λ§Œλ“€μ–΄λ‚΄λŠ” 방식
  • μžλ°”μ—μ„œλŠ” λžŒλ‹€μ‹, ν•¨μˆ˜ν˜• μΈν„°νŽ˜μ΄μŠ€, 슀트림 APIλ₯Ό ν™œμš©ν•˜μ—¬ κ΅¬ν˜„
  • μ„ μ–Έν˜• ν”„λ‘œκ·Έλž˜λ° νŒ¨λŸ¬λ‹€μž„μ— κ°€κΉŒμ›€ β†’ 가독성, μœ μ§€λ³΄μˆ˜μ„±, 병렬 μ²˜λ¦¬μ— 유리

βœ… ν•¨μˆ˜ν˜• μΈν„°νŽ˜μ΄μŠ€ μ •μ˜ 및 μ‚¬μš©

@FunctionalInterface
interface Func1 {
    void say(String message); // 좔상 λ©”μ„œλ“œ 1개만 μ‘΄μž¬ν•΄μ•Ό 함
}

@FunctionalInterface
interface Func2 {
    int sum(Integer... args); // κ°€λ³€ 인자 ν•©μ‚°
}

@FunctionalInterface
interface Func3 {
    List<Integer> createListDesc(int... args); // μ •μˆ˜ λ°°μ—΄ β†’ λ‚΄λ¦Όμ°¨μˆœ List λ°˜ν™˜
}

βœ… ν•¨μˆ˜ν˜• μΈν„°νŽ˜μ΄μŠ€ μ‚¬μš© 예제

public class C01FunctionalInterfaceMain {
    public static void main(String[] args) {
        // λ¬Έμžμ—΄ 좜λ ₯ ν•¨μˆ˜
        Func1 func1 = (msg) -> System.out.println("λ©”μ‹œμ§€: " + msg);
        func1.say("Hello!");

        // 숫자 ν•©μ‚° ν•¨μˆ˜
        Func2 func2 = (nums) -> Arrays.stream(nums).reduce(0, Integer::sum);
        System.out.println("합계: " + func2.sum(10, 20, 30));

        // μ •μˆ˜ 배열을 λ‚΄λ¦Όμ°¨μˆœμœΌλ‘œ μ •λ ¬ ν›„ List둜 λ³€ν™˜
        Func3 func3 = (nums) -> Arrays.stream(nums)
                                      .boxed()
                                      .sorted((a, b) -> b - a)
                                      .collect(Collectors.toList());
        System.out.println("λ‚΄λ¦Όμ°¨μˆœ 리슀트: " + func3.createListDesc(5, 3, 9, 1));
    }
}

βœ… andThen()을 μ΄μš©ν•œ ν•¨μˆ˜ μ—°κ²°

Function<Integer, Integer> square = x -> x * x;
Function<Integer, Integer> doubleIt = x -> x * 2;

// square ν›„ doubleIt μˆ˜ν–‰: (x * x) * 2
Function<Integer, Integer> squareThenDouble = square.andThen(doubleIt);

System.out.println(squareThenDouble.apply(5)); // 25 β†’ 50

πŸ“Œ andThen() μš”μ•½
f.andThen(g)λŠ” μˆ˜ν•™μ μœΌλ‘œ g(f(x)) λ₯Ό μ˜λ―Έν•œλ‹€.


βœ… κ³ μ°¨ ν•¨μˆ˜ & 컀링(Currying)

// ν•¨μˆ˜λ₯Ό λ¦¬ν„΄ν•˜λŠ” ν•¨μˆ˜
Function<Integer, Function<Integer, Integer>> curriedAdd = x -> y -> x + y;

System.out.println(curriedAdd.apply(10).apply(20)); // 30

// 3단계 컀링
Function<Integer, Function<Integer, Function<Integer, Integer>>> func3args =
    x -> y -> z -> x + y + z;

System.out.println(func3args.apply(1).apply(2).apply(3)); // 6

βœ… Object 리슀트 필터링 & μ—°μ‚° μ‹€μŠ΅

// List<Object> 쀑 Integer만 골라 ν•©μ‚°
Function<List<Object>, Integer> sumOnlyIntegers = list -> 
    list.stream()
        .filter(el -> el instanceof Integer)
        .map(el -> (Integer) el)
        .reduce(0, Integer::sum);

βœ… 사칙연산 클래슀 예제 (Calc)

@FunctionalInterface
interface Functional {
    Integer execute(int... args);
}

class Calc {
    Functional sum, sub, mul, div;

    Calc() {
        sum = (args) -> Arrays.stream(args).reduce(0, Integer::sum);

        sub = (args) -> Arrays.stream(args)
                              .boxed()
                              .sorted((a, b) -> b - a)
                              .reduce((a, b) -> a - b)
                              .orElse(0);

        mul = (args) -> Arrays.stream(args).reduce(1, (a, b) -> a * b);

        div = (args) -> Arrays.stream(args)
                              .boxed()
                              .sorted((a, b) -> b - a)
                              .mapToInt(Integer::intValue)
                              .reduce((a, b) -> a / b)
                              .orElse(0);
    }
}
// μ‹€ν–‰ 예제
Calc calc = new Calc();
System.out.println("λ§μ…ˆ: " + calc.sum.execute(10, 20, 30)); // 60
System.out.println("λΊ„μ…ˆ: " + calc.sub.execute(100, 20, 10)); // 70
System.out.println("κ³±μ…ˆ: " + calc.mul.execute(2, 3, 4)); // 24
System.out.println("λ‚˜λˆ—μ…ˆ: " + calc.div.execute(100, 2, 5)); // 10

2️⃣ μ–΄λ…Έν…Œμ΄μ…˜ (Annotation)

βœ… μ–΄λ…Έν…Œμ΄μ…˜μ΄λž€?

  • ν”„λ‘œκ·Έλž¨, 컴파일러, λΉŒλ“œ 도ꡬ 등에 λΆ€κ°€ 정보λ₯Ό μ œκ³΅ν•˜λŠ” 메타데이터
  • @ 기호둜 μ‹œμž‘ν•˜λ©° 클래슀, λ©”μ„œλ“œ, ν•„λ“œ 등에 뢙일 수 있음

βœ… μ–΄λ…Έν…Œμ΄μ…˜μ˜ λΆ„λ₯˜

βœ”οΈ ν‘œμ€€ μ–΄λ…Έν…Œμ΄μ…˜

μ–΄λ…Έν…Œμ΄μ…˜μ„€λͺ…
@Overrideμ˜€λ²„λΌμ΄λ”© 확인
@Deprecated더 이상 μ‚¬μš©λ˜μ§€ μ•ŠμŒ
@FunctionalInterfaceν•¨μˆ˜ν˜• μΈν„°νŽ˜μ΄μŠ€
@SuppressWarningsκ²½κ³  μ–΅μ œ
@SafeVarargsκ°€λ³€ 인자 μ œλ„€λ¦­ κ²½κ³  μ–΅μ œ

βœ”οΈ 메타 μ–΄λ…Έν…Œμ΄μ…˜

μ–΄λ…Έν…Œμ΄μ…˜μ„€λͺ…
@Retentionμœ μ§€ μ •μ±… (SOURCE, CLASS, RUNTIME)
@Target적용 μœ„μΉ˜ (CLASS, METHOD λ“±)
@Documentedjavadoc 포함 μ—¬λΆ€
@Inherited상속 μ—¬λΆ€
@Repeatable반볡 적용 κ°€λŠ₯

βœ… μ‚¬μš©μž μ •μ˜ μ–΄λ…Έν…Œμ΄μ…˜

@Retention(RetentionPolicy.RUNTIME) // λŸ°νƒ€μž„ μœ μ§€
@Target({ElementType.TYPE, ElementType.METHOD}) // 클래슀/λ©”μ„œλ“œμ— 적용 κ°€λŠ₯
public @interface CustomAnnotation {
    String value() default "";
    int number() default 0;
    boolean isOpen() default true;
}

βœ… μ–΄λ…Έν…Œμ΄μ…˜ 적용 예제

@CustomAnnotation(value = "HELLO WORLD", number = 5, isOpen = true)
class Simple {
    String v1;
    int v2;

    Simple() {
        CustomAnnotation ref = this.getClass().getAnnotation(CustomAnnotation.class);
        System.out.println("value: " + ref.value());
        System.out.println("number: " + ref.number());
        System.out.println("isOpen: " + ref.isOpen());

        this.v1 = ref.value();
        this.v2 = ref.number();
    }

    @Override
    public String toString() {
        return "Simple[v1=" + v1 + ", v2=" + v2 + "]";
    }
}

βœ… μ‹€ν–‰ μ½”λ“œ

public class Main {
    public static void main(String[] args) {
        Simple s = new Simple();
        System.out.println(s);
    }
}

πŸ”Ή 좜λ ₯ κ²°κ³Ό

value: HELLO WORLD
number: 5
isOpen: true
Simple[v1=HELLO WORLD, v2=5]

πŸ”₯ 였늘의 μš”μ•½

주제배운 λ‚΄μš©
ν•¨μˆ˜ν˜• ν”„λ‘œκ·Έλž˜λ°λžŒλ‹€μ‹, ν•¨μˆ˜ν˜• μΈν„°νŽ˜μ΄μŠ€, 슀트림, κ³ μ°¨ ν•¨μˆ˜, 컀링
ν•¨μˆ˜ μ—°κ²°andThen() 으둜 ν•¨μˆ˜ 체이닝
Object 필터링filter + map + reduce 둜 νƒ€μž…λ³„ 처리
μ–΄λ…Έν…Œμ΄μ…˜κΈ°λ³Έ + 메타 + μ‚¬μš©μž μ •μ˜ μ–΄λ…Έν…Œμ΄μ…˜
λ¦¬ν”Œλ ‰μ…˜getAnnotation() 으둜 λŸ°νƒ€μž„μ— 정보 μΆ”μΆœ

πŸ’­ λŠλ‚€ 점

μ˜€λŠ˜μ€ μžλ°”μ˜ 두 핡심 주제인 ν•¨μˆ˜ν˜• ν”„λ‘œκ·Έλž˜λ°κ³Ό μ–΄λ…Έν…Œμ΄μ…˜μ„ μ‹€μŠ΅ν•˜λ©° κ°œλ…μ„ ν™•μ‹€νžˆ μ΅ν˜”λ‹€.
특히, λžŒλ‹€μ‹κ³Ό andThen()을 톡해 ν•¨μˆ˜λ₯Ό μ‘°λ¦½ν•˜λ“― μ‚¬μš©ν•  수 μžˆλ‹€λŠ” 것이 맀우 ν₯λ―Έλ‘œμ› λ‹€.
λ˜ν•œ, μ–΄λ…Έν…Œμ΄μ…˜μ„ 직접 μ •μ˜ν•˜κ³  λ¦¬ν”Œλ ‰μ…˜μœΌλ‘œ 값을 μ½λŠ” 과정은
μ‹€μ œ ν”„λ ˆμž„μ›Œν¬(Spring λ“±)κ°€ μ–΄λ–»κ²Œ μž‘λ™ν•˜λŠ”μ§€λ₯Ό μ΄ν•΄ν•˜λŠ” 데 큰 도움이 λ˜μ—ˆλ‹€.

이제 μ‹€λ¬΄μ—μ„œλ„ ν•¨μˆ˜ν˜• 사고와 μ–΄λ…Έν…Œμ΄μ…˜ 기반 섀정을 μžμ‹  있게 ν™œμš©ν•  수 μžˆμ„ 것 κ°™λ‹€! πŸ’ͺ


profile
Here, My Pale Blue.🌏

0개의 λŒ“κΈ€