람다식(Lambda Expressions)
자바는 객체 지향 프로그래밍 언어이지만 함수적 프로그래밍을 위해 자바8부터 람다식을 지원.
람다식의 형태는 매개변수를 가진 코드 블록이지만 런타임 시에는 익명 구현 객체를 생성함.
람다 표현식(Lambda Expression)은 간결하게 코드를 작성하기 위한 기능으로, 함수적 인터페이스와 함께 사용됩니다.
함수적 인터페이스(Functional Interface)는 람다를 활용하기 위한 기본적인 구조를 제공합니다.
### 함수적 인터페이스란?
함수적 인터페이스는 추상 메서드가 단 하나만 선언된 인터페이스를 의미합니다.
함수적 인터페이스는 람다 표현식이나 메서드 참조를 사용하여 그 구현을 제공할 수 있습니다.
#### 특징
1. @FunctionalInterface 어노테이션:
- 명시적으로 함수적 인터페이스임을 선언하기 위해 사용합니다.
- 이 어노테이션은 컴파일러가 해당 인터페이스가 정확히 하나의 추상 메서드를 가지고 있는지 확인하도록 강제합니다.
- 함수적 인터페이스는 `@FunctionalInterface` 없이도 동작할 수 있지만, 이를 추가하면 실수를 방지할 수 있습니다.
2. 단일 추상 메서드(Single Abstract Method, SAM):
- 반드시 하나의 추상 메서드를 가져야 합니다.
- 기존의 `Object` 클래스 메서드(`equals()`, `hashCode()`, `toString()` 등)는 함수적 인터페이스에 포함되지 않습니다.
3. 람다와 함께 사용:
- 함수적 인터페이스의 단일 메서드의 구현을 람다 표현식으로 제공할 수 있습니다.
### 함수적 인터페이스 예제
#### 1. 사용자 정의 함수적 인터페이스
@FunctionalInterface
interface Calculator {
int calculate(int x, int y); // 단 하나의 추상 메서드
}
public class LambdaExample {
public static void main(String[] args) {
// 람다 표현식으로 인터페이스 구현
Calculator add = (x, y) -> x + y;
Calculator subtract = (x, y) -> x - y;
System.out.println("더하기: " + add.calculate(10, 5)); // 출력: 15
System.out.println("빼기: " + subtract.calculate(10, 5)); // 출력: 5
}
}
#### 2. Java 표준 함수적 인터페이스
Java 8부터 제공되는 패키지 `java.util.function`에서 다양한 표준 함수적 인터페이스를 제공합니다. 대표적인 예:
- `Predicate<T>`: 조건을 검사하여 `true` 또는 `false`를 반환.
- `Function<T, R>`: 입력을 받아 특정 출력으로 매핑.
- `Consumer<T>`: 입력을 소비(처리)하고 반환값 없음.
- `Supplier<T>`: 값을 생성하고 반환.
### 람다 표현식과 함수적 인터페이스 관계
람다 표현식은 함수적 인터페이스의 단일 추상 메서드를 구현한 것으로 간주됩니다. 이를 통해 클래스를 정의하거나 익명 클래스 객체를 생성하지 않고도 간결한 코드를 작성할 수 있습니다.
#### 표준 함수적 인터페이스와 람다 예제
import java.util.function.Function;
import java.util.function.Predicate;
public class BuiltInFunctionalInterfaceExample {
public static void main(String[] args) {
// Predicate: 문자열이 빈 문자열인지 확인
Predicate<String> isEmpty = s -> s.isEmpty();
System.out.println(isEmpty.test("")); // 출력: true
// Function: 문자열을 정수로 변환
Function<String, Integer> stringToLength = s -> s.length();
System.out.println(stringToLength.apply("Lambda")); // 출력: 6
}
}
### 장점
1. 코드 간소화:
- 불필요한 익명 클래스 사용을 줄이고, 간결한 람다 표현식으로 대체 가능.
2. 가독성 향상:
- 함수적 프로그래밍 스타일을 지원하여 코드 가독성이 높아짐.
3. 재사용성:
- 표준 함수적 인터페이스를 활용하면 공통 로직을 재사용 가능.
### @FunctionalInterface의 역할
`@FunctionalInterface`는 선택사항이지만, 이를 사용하면 컴파일러가 단일 추상 메서드(SAM)만 유지되도록 강제합니다. 함수적 인터페이스가 아닌 방식으로 오용되는 것을 방지합니다.
@FunctionalInterface
interface InvalidFunctionalInterface {
void method1();
void method2(); // 컴파일 오류: 함수적 인터페이스는 단 하나의 추상 메서드만 가질 수 있음
}
### 요약
1. 함수적 인터페이스는 단일 추상 메서드를 가지며, Java 람다 표현식의 기반이 됩니다.
2. Java 표준 함수적 인터페이스(`Predicate`, `Function`, `Consumer`, `Supplier` 등)를 사용하면 복잡한 작업을 간소화할 수 있습니다.
3. `@FunctionalInterface`를 사용하면 함수적 인터페이스를 명시적으로 정의하고 컴파일러 검증을 받을 수 있습니다.
1. 람다식은 "(매개변수) -> {실행코드}" 형태로 작성됨.
Runable runable = new Runable() { public void run() { ... } }; // 람다식 Runable runable = () -> { ... };
2. 람다식 기본 문법
(매개변수, ...) -> { 실행코드; };
(int a) -> { System.out.println(a); }
자바는 매개변수 타입을 추론할 수 있으므로 명시적으로 작성하지 않아도 됩니다. 타입 생략은 코드를 더 간결하게 만듭니다.
(a) -> { System.out.println(a); }
하나의 매개변수만 있다면 괄호() 생략이 가능함. 매개변수가 없는 경우는 괄호()를 반드시 사용해야 됨.
a -> { System.out.println(a); }
() -> { System.out.println(a); } // 매개변수가 없는 경우 괄호 필수임
return문만 있는 경우 return문 생략이 가능함.
(x, y) -> { return x + y; } // 아래처럼 return 생략 가능
(x, y) -> x + y