자바에서 익명 객체(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();
}
}
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(); // 결과: 버튼이 클릭되었습니다!
}
}
람다(Lambda)는 자바 8부터 도입된 익명 함수를 간결하게 표현하는 문법으로, 보통 함수형 인터페이스를 구현할 때 사용됩니다. 즉, 메서드를 하나만 갖는 인터페이스의 구현을 코드 블록 없이 매개변수 -> 실행문 형식으로 간단히 작성할 수 있도록 해줍니다. 람다는 코드의 간결성과 가독성을 높이며, 특히 컬렉션 처리나 스트림 API와 함께 사용할 때 매우 유용하게 쓰입니다. 예를 들어, list.forEach(item -> System.out.println(item));처럼 반복 작업을 직관적으로 표현할 수 있습니다.
(매개변수) -> { 실행문 }
함수형 인터페이스(Functional Interface)는 오직 하나의 추상 메서드만 가지는 인터페이스로, 자바에서 람다 표현식의 대상이 되는 인터페이스입니다. 이 인터페이스를 구현할 때는 별도의 클래스 없이 람다로 간단히 구현할 수 있어 코드가 간결해집니다. @FunctionalInterface 어노테이션을 사용하면 컴파일러가 해당 인터페이스가 함수형 인터페이스임을 검증해주며, 실수로 두 개 이상의 추상 메서드를 선언했을 때 오류를 발생시켜줍니다. 대표적인 예로는 Runnable, Callable, Comparator, Consumer 등이 있으며, 자바 8부터는 java.util.function 패키지에 다양한 기본 함수형 인터페이스가 제공됩니다.
@FunctionalInterface
interface MyPrinter {
void print(String message);
}
※ 함수형 인터페이스에는 @FunctionalInterface 어노테이션을 붙이는 것이 관례입니다.
@FunctionalInterface
interface Hello {
void sayHello();
}
public class Main {
public static void main(String[] args) {
Hello h = () -> System.out.println("안녕하세요!");
h.sayHello();
}
}
@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("람다 표현식!");
}
}
@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
}
}
@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
}
}
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();
}
}