특징
- 익명 클래스에 비해 훨씬 간단하게 작성 가능해서 코드가 간결해짐
- 복잡한 코드가 단순화돼서 가독성 향상
- 일회성으로 사용되는 함수 정의를 간단히 처리 가능
- 다른 함수의 매개 변수로 전달하기 용이
- 다양한 상황에서 유연한 활용 가능
- 특히 컬렉션과 스트림 API를 사용할 때 유용
제약
- 함수형 인터페이스만 지원
- 추상 메서드가 2개 이상인 인터페이스에는 사용 불가
- 디버깅 어려움
- 복잡한 람다식은 디버깅이 까다로울 수 있음
- 가독성 문제
- 너무 긴 람다식 사용하면 오히려 가독성 떨어질 수 있음
람다는 인터페이스로 만듦
- 함수형 인터페이스를 구현하기 위해 사용
- 함수형 인터페이스는 하나의 추상 메서드만 가지는 인터페이스로 정의됨
인터페이스에서는 메서드가 하나만 존재해야 함
- 하나의 추상 메서드만 가지는 함수형 인터페이스를 구현
- 하지만 하나의 추상 메서드 외에도 여러 개의 디폴트 메서드나 정적 메서드를 가질 수 있음
메서드가 인터페이스를 매개 변수로 받고 있으면, 행위를 줘야함
- 함수형 인터페이스를 매개 변수로 받는 메서드는 실제로 특정 동작이나 행위를 전달하는 의미로 사용
- 높은 수준의 추상화를 통해 행위를 메서드에 전달하는 방식
람다에서는 매개 변수에 타입 생략 가능
- ( ) → { }
- (매개 변수) → {실행 코드}
- 매개 변수 : 함수의 입력 값
- → : 매개 변수와 함수 본체를 구분하는 화살표
- 실행 코드 : 람다식의 본체, 함수의 동작을 정의
- 매개 변수 타입 생략 가능
- 괄호를 해도 되고 안 해도 되는데 값(매개 변수)이 없으면 괄호 있어야 함
- 컴파일러는 람다식의 문맥으로부터 타입을 추론할 수 있음
// 매개 변수 타입 생략 안 함 => 괄호 존재
MyConsumer<Integer> consumer = (data) -> {
System.out.println(data);
};
// 매개 변수 타입 생략 => 괄호 생략
MyConsumer<Integer> consumer = data -> {
System.out.println(data);
};@FunctionalInterface(런타임 실행) 표시 가능
- 함수형 인터페이스로 명시
- @FunctionalInterface 어노테이션으로 해당 인터페이스가 함수형 인터페이스임을 명시적으로 선언 가능
- 컴파일러 체크
- 인터페이스에 추상 메서드가 두 개 이상 존재할 경우 컴파일 오류 발생시켜서 함수형 인터페이스의 규칙 위반하지 않도록 함
종류
MyConsumer<T>
- 입력만 받고 출력이 없는 연산 수행
// 입력만 받고 출력이 없는 연산 수행
@FunctionalInterface
public interface MyConsumer<T> {
void accept(T data);
}MySupplier<T>
- 입력 없이 값 반환(return)
// 입력 없이 값을 반환(return) => 공급자
// 입력이 없으니 매개변수도 없음 => 반환은 해야하니까 generic(T) 필요
@FunctionalInterface
public interface MySupplier<T> {
T get();
}MyFunction<T, R>
- 입력을 받아서 결과 반환(return)
// 입력을 받아서 결과를 반환
// 입력과 결과 다 필요하니까 generic 2개
@FunctionalInterface
public interface MyFunction<T,R> {
R apply(T t);
}MyPredicate<T>
- 입력을 받아서 논리값(boolean) 반환(return)
// 입력을 받아 논리값(boolean)을 반환
// generic(T)(boolean) 반환
@FunctionalInterface
public interface MyPredicate<T> {
boolean test(T t);
}종류 별 활용 및 실행 결과
// 1. 람다는 인터페이스로 만듦
// 2. 인터페이스에서는 메소드가 하나만 존재해야 함
// 3. 메소드가 인터페이스를 매개변수로 받고 있으면, 행위를 주세요!!
// 4. 람다에서는 매개변수에 타입을 생략 가능
// 5. @FunctionalInterface(런타임 실행) 표시 가능
public class App {
public static void main(String[] args) {
// 람다식 : () -> {}
// 4-1. ()안은 매개변수인데 괄호를 해도 되고 안해도 되고
// 물론 값(매개변수)이 없으면 괄호 있어야함
MyConsumer<Integer> r1 = (data) -> {
System.out.println("소비할 데이터 : " + data);
};
r1.accept(1); // 소비할 데이터 : 1 출력
// good 문자열 반환하는 람다식
// 람다표현식 : 표현식은 무조건 반환(return)이 됨
MySupplier<String> r2 = () -> {
return "good";
};
// 람다식은 중괄호와 return을 생략해도 자동 반환(return)이 됨
MySupplier<String> r3 = () -> "good";
System.out.println(r2.get() + "/" + r3.get()); // good / good 출력
// 받은 문자열의 길이값을 반환하는 람다식
MyFunction<String, Integer> r4 = (String s) -> s.length();
System.out.println("Length of 'hello': " + r4.apply("hello")); // Length of 'hello': 5 출력
// 숫자가 짝수인지 확인하는 람다식
MyPredicate<Integer> r5 = (Integer x) -> x % 2 == 0;
System.out.println(r5.apply(3)); // false 출력
}
}
Share article