상세 컨텐츠

본문 제목

람다식

백엔드/Java

by Ryuzy 2025. 5. 25. 16:22

본문

728x90
반응형

1. 익명 객체

자바에서 익명 객체(anonymous object)는 이름이 없는 클래스를 정의하고 그 객체를 한 번만 사용하고자 할 때 사용하는 기법입니다. 보통은 인터페이스나 추상 클래스를 구현/상속하면서 동시에 객체로 생성할 때 사용되며, 이때 객체를 표현하기 위한 별도 클래스의 이름 없이 직접 정의하고 생성하기 때문에 "익명" 객체라 부릅니다.

abstract class Animal {
    public abstract void speak();
}

public class Main {
    public static void main(String[] args) {
        // 익명 객체 생성 (클래스 이름 없이 바로 구현 및 인스턴스 생성)
        Animal tiger = new Animal() {
            @Override
            public void speak() {
                System.out.println("어흥! 나는 호랑이야.");
            }
        };

        Animal dog = new Animal() {
            @Override
            public void speak() {
                System.out.println("멍멍! 나는 강아지야.");
            }
        };

        tiger.speak();
        dog.speak();
    }
}
  • Animal이라는 추상 클래스를 구현하는 이름 없는 클래스를 만들어서 곧바로 객체를 생성함
  • 메서드 오버라이딩도 바로 가능함

 

interface ButtonClickListener {
    void onClick();
}

public class Main {
    public static void main(String[] args) {
        ButtonClickListener listener = new ButtonClickListener() {
            @Override
            public void onClick() {
                System.out.println("버튼이 클릭되었습니다!");
            }
        };

        listener.onClick();  // 결과: 버튼이 클릭되었습니다!
    }
}

 

 

2. 람다

람다(Lambda)는 자바 8부터 도입된 익명 함수를 간결하게 표현하는 문법으로, 보통 함수형 인터페이스를 구현할 때 사용됩니다. 즉, 메서드를 하나만 갖는 인터페이스의 구현을 코드 블록 없이 매개변수 -> 실행문 형식으로 간단히 작성할 수 있도록 해줍니다. 람다는 코드의 간결성과 가독성을 높이며, 특히 컬렉션 처리나 스트림 API와 함께 사용할 때 매우 유용하게 쓰입니다. 예를 들어, list.forEach(item -> System.out.println(item));처럼 반복 작업을 직관적으로 표현할 수 있습니다.

(매개변수) -> { 실행문 }

 

  • 매개변수가 1개이면 괄호 () 생략 가능
  • 실행문이 한 줄이면 {}와 return 생략 가능

 

 

함수형 인터페이스

함수형 인터페이스(Functional Interface)는 오직 하나의 추상 메서드만 가지는 인터페이스로, 자바에서 람다 표현식의 대상이 되는 인터페이스입니다. 이 인터페이스를 구현할 때는 별도의 클래스 없이 람다로 간단히 구현할 수 있어 코드가 간결해집니다. @FunctionalInterface 어노테이션을 사용하면 컴파일러가 해당 인터페이스가 함수형 인터페이스임을 검증해주며, 실수로 두 개 이상의 추상 메서드를 선언했을 때 오류를 발생시켜줍니다. 대표적인 예로는 Runnable, Callable, Comparator, Consumer 등이 있으며, 자바 8부터는 java.util.function 패키지에 다양한 기본 함수형 인터페이스가 제공됩니다.

@FunctionalInterface
interface MyPrinter {
    void print(String message);
}

※ 함수형 인터페이스에는 @FunctionalInterface 어노테이션을 붙이는 것이 관례입니다.

 

1. 매개변수 없음, 반환값 없음

@FunctionalInterface
interface Hello {
    void sayHello();
}

public class Main {
    public static void main(String[] args) {
        Hello h = () -> System.out.println("안녕하세요!");
        h.sayHello();
    }
}

 

2. 매개변수 있음, 반환값 없음

@FunctionalInterface
interface Printer {
    void print(String message);
}

public class Main {
    public static void main(String[] args) {
        Printer p = msg -> System.out.println("출력: " + msg);
        p.print("람다 표현식!");
    }
}

 

3. 매개변수 여러 개, 반환값 있음

@FunctionalInterface
interface Adder {
    int add(int a, int b);
}

public class Main {
    public static void main(String[] args) {
        Adder adder = (a, b) -> a + b;
        System.out.println("합계: " + adder.add(5, 7)); // 12
    }
}

 

4. 실행문 여러 줄 (중괄호 {}와 return 사용)

@FunctionalInterface
interface Comparator {
    int compare(int a, int b);
}

public class Main {
    public static void main(String[] args) {
        Comparator comp = (a, b) -> {
            System.out.println("비교 중...");
            return Integer.compare(a, b);
        };

        System.out.println("결과: " + comp.compare(10, 20)); // -1
    }
}

 

5. 람다식과 컬렉션 API

import java.util.Arrays;
import java.util.List;

public class Main {
    public static void main(String[] args) {
        List<String> fruits = Arrays.asList("사과", "바나나", "오렌지");

        // forEach에 람다 적용
        fruits.forEach(fruit -> System.out.println("과일: " + fruit));
    }
}

 

랜덤 퀴즈 게임

import java.util.*;

@FunctionalInterface
interface Checker {
    boolean check(String userAnswer, String correctAnswer);
}

public class SimpleQuizGame {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);

        // 문제-정답 Map
        Map<String, String> questionMap = new LinkedHashMap<>();
        questionMap.put("자바에서 문자열을 나타내는 클래스는?", "String");
        questionMap.put("자바에서 반복문에 사용하는 키워드는?", "for");
        questionMap.put("자바에서 클래스를 정의할 때 사용하는 키워드는?", "class");
        questionMap.put("자바에서 상속을 표현하는 키워드는?", "extends");
        questionMap.put("자바의 논리 연산자 중 하나는?", "&&");

        // 문제 랜덤화
        List<Map.Entry<String, String>> entries = new ArrayList<>(questionMap.entrySet());
        Collections.shuffle(entries);

        // 채점 기준: equalsIgnoreCase 고정
        Checker checker = (user, correct) -> user.trim().equalsIgnoreCase(correct);

        System.out.println("\n🔍 퀴즈 게임 시작!\n");

        int score = 0;
        for (Map.Entry<String, String> entry : entries) {
            String question = entry.getKey();
            String answer = entry.getValue();

            System.out.println("문제: " + question);
            System.out.print("당신의 답변: ");
            String userInput = scanner.nextLine();

            if (checker.check(userInput, answer)) {
                System.out.println("✅ 정답!\n");
                score++;
            } else {
                System.out.println("❌ 오답! 정답은 [" + answer + "]입니다.\n");
            }
        }

        System.out.println("🎉 게임 종료! 당신의 점수는 " + score + "점입니다.");
        scanner.close();
    }
}

 

728x90
반응형

'백엔드 > Java' 카테고리의 다른 글

스레드  (1) 2025.05.28
스트림  (0) 2025.05.25
DTO와 VO  (0) 2025.05.23
제네릭  (0) 2025.05.23
java.lang 패키지  (0) 2025.05.21

관련글 더보기