Chapter 3 - 5 : 람다
1. 익명 클래스
- 익명 클래스는 이름이 없는 클래스.
- 별도의 클래스 파일을 만들지 않고 코드 내에서 일회성으로 정의해 사용하기 때문에 이름이 없다고 부름.
- 인터페이스, 클래스(일반, 추상)의 구현과 상속을 활용해 익명 클래스를 구현할 수 있음.
→ 람다에서는 인터페이스를 사용한 익명 클래스가 활용됨.
💡인터페이스를 활용한 익명 클래스 예제
- 익명 클래스를 코드 내에서 직접 구현하기 때문에 클래스를 만들 필요가 없음. → 하지만 코드가 길어짐.
Calculator.java - Interface
public interface Calculator {
int sum(int a, int b);
}
Main.java
public class Main {
public static void main(String[] args) {
// ✅ 익명 클래스 활용
Calculator calculator1 = new Calculator() {
@Override
public int sum(int a, int b) {
return a + b;
}
};
int ret1 = calculator1.sum(1, 1);
System.out.println("ret1 = " + ret1);
}
}
● 파일이 아니라 코드 내에 있기 때문에 클래스 이름이 존재하지 않음 → 그게 익명 클래스.
● 필요할 때만 일회성으로 인터페이스 기반으로 구현해서 인스턴스를 변수에 담아 활용.
2. 람다(Lambda)
- 익명 클래스를 더 간결하게 표현하는 문법.
- 함수형 인터페이스를 통해서 구현하는 것을 권장함.
→ 하나의 추상 메서드만 가져야하기 때문.
→ 하나의 추상 메서드를 가진 일반 인터페이스를 통해서도 사용 가능.
// 람다 표현식
Calculator calculator1 = (a, b) -> a + b;
// 익명클래스
Calculator calculator1 = new Calculator() {
@Override
public int sum(int a, int b) {
return a + b;
}
};
● 람다 표현식을 보고 자바 컴파일러가 컴파일 시점에 아래 익명 클래스를 내부적으로 만들어줌.
● (a, b) 가 매개변수를 의미함.
● " -> a + b; " 가 함수 메서드 구현 내용을 나타내고 있음.
● " (a, b) -> a + b; " → a와 b를 넣으면 a + b 를 반환한다는 뜻.
Calculator.java - 함수형 인터페이스
@FunctionalInterface // ✅ 함수형 인터페이스 선언
public interface Calculator {
int sum(int a, int b); // ✅ 오직 하나의 추상 메서드만 선언해야합니다.
}
● 람다식을 보고 추상메서드를 확인한 후, 자동으로 추론해주는 것.
● 함수형 인터페이스에서는 추상 메서드를 한 개만 구현할 수 있도록 강제로 제한함!!
→ 그래서 람다식을 사용할 때 함수형 인터페이스를 사용하라고 권장하는 것!!
2 - 1. 람다식을 활용한 익명 클래스 변환 방법
- 컴파일 시점에 컴파일러가 (a, b) -> a + b 람다 표현식을 보고 sum() 메서드를 가진 익명 클래스를 구현함.
- Calculator 인터페이스에 추상 메서드가 하나뿐이기 때문에 컴파일러는 (a, b) -> a + b 람다 표현식이 sum() 메서드라고 추론 가능함.
⚠️ 람다 사용 시 주의사항
- 람다식을 활용할 때는 꼭 함수형 인터페이스를 활용해야함!
- 함수형 인터페이스는 단 하나의 추상 메서드만 가지도록 강제하는 어노테이션(@FunctionalInterface)을 붙임.
- 람다식에서는 함수형 인터페이스가 활용됨.
- 인터페이스에 두 개 이상의 추상 메서드가 존재하면 컴파일러가 어떤 메서드를 구현하는지 모호해지기 때문.
- 예를 들어 오버로딩(Overloading) 기능을 통해 같은 이름의 sum() 메서드를 여러 형태로 정의한다면 람다 표현식이 어떤 메서드를 구현하는 것인지 명확하지 않아 모호성 발생 가능.
public interface Calculator {
int sum(int a, int b); // ✅ 선언 가능
int sum(int a, int b, int c); // ⚠️ 오버로딩으로 선언 가능 모호성 발생!
}
@FunctionalInterface // ✅ 함수형 인터페이스 선언
public interface Calculator {
int sum(int a, int b); // ✅ 오직 하나의 추상 메서드만 선언해야합니다.
int sum(int a, int b, int c); // ❌ 선언 불가 에러발생!
}
오버로딩(Overloading) vs 오버라이딩(Overriding)
- 오버로딩은 같은 클래스나 인터페이스 내에서 동일한 메서드 이름을 사용해서 선언하는 기능.
→ 매개변수의 개수나 타입, 순서는 다르게 선언해야함.
- 오버라이딩은 부모 클래스에 정의된 메서드를 자식클래스에서 재정의하는 것.
2 - 2. 람다식을 매개변수로 전달하는 방법
- 익명 클래스를 변수에 담아 전달.
- 람다식 없이 직접 객체를 생성해서 전달하는 방식.
- 클래스의 익명 객체를 만든 다음에 매개변수로 전달함.
public class Main {
public static int calculate(int a, int b, Calculator calculator) {
return calculator.sum(a, b);
}
public static void main(String[] args) {
Calculator cal1 = new Calculator() {
@Override
public int sum(int a, int b) {
return a + b;
}
};
// ✅ 익명 클래스를 변수에 담아 전달
int ret3 = calculate(3, 3, cal1);
System.out.println("ret3 = " + ret3); // 출력: ret3 = 6
}
}
- 람다식을 변수에 담아 전달.
- 람다식을 변수에 담아 매개변수로 전달하는 방식.
- 람다식을 전달하면 calculate() 메서드의 매개변수의 타입으로 Calculator 인터페이스를 구현했는지 추론되기 때문에 람다식 전달 가능.
public class Main {
public static int calculate(int a, int b, Calculator calculator) {
return calculator.sum(a, b);
}
public static void main(String[] args) {
Calculator cal2 = (a, b) -> a + b;
// ✅ 람다식을 변수에 담아 전달
int ret4 = calculate(4, 4, cal2);
System.out.println("ret4 = " + ret4); // 출력: ret4 = 8
}
}
- 람다식을 직접 전달.
- 마찬가지로 calculate() 메서드의 매개변수의 타입으로 Calculator 인터페이스를 구현했는지 추론됨.
public class Main {
public static int calculate(int a, int b, Calculator calculator) {
return calculator.sum(a, b);
}
public static void main(String[] args) {
// ✅ 람다식을 직접 매개변수로 전달
int ret5 = calculate(5, 5, (a, b) -> a + b);
System.out.println("ret5 = " + ret5); // 출력: ret5 = 10
}
}
'스파르타 내일배움캠프 > TIL(Today I learned)' 카테고리의 다른 글
25.03.19 TIL - Web (2) | 2025.03.19 |
---|---|
25.03.18 TIL - 네트워크 (5) | 2025.03.18 |
25.03.14 TIL - 키오스크 과제 회고 (3) | 2025.03.14 |
25.03.13 TIL - Lv3. 키오스크 과제 (2) | 2025.03.13 |
25.03.12 TIL - 컬렉션 (2) | 2025.03.12 |