rudu_std
람다 표현식 (Lambda Expression) 본문
람다 표현식 (Lambda Expression)
람다 표현식(lambda expression)이란 함수형 프로그래밍을 구성하기 위한 함수식이며,
간단히 말해 자바의 메소드를 간결한 함수 식으로 표현한 것.
—람다식의 장점과 제한사항—
장점:
- 간결함 : 익명 클래스의 불필요한 코드 제거.
- 가독성 : 코드가 짧아져서 더 읽기 쉬워짐.
- 함수형 프로그래밍 지원 : 순수 함수 스타일의 코딩 가능.
제한사항:
- 디버깅 : 람다식 내부의 코드를 디버깅하기 어려울 수 있음.
- 명확성 : 지나치게 복잡한 람다식은 오히려 가독성을 떨어뜨릴 수 있음.
- 제한된 사용 범위 : 람다식은 함수형 인터페이스와만 사용 가능.
람다식은 자바에서 함수형 인터페이스를 구현할 때 사용됩니다. 따라서 람다식은 함수형 인터페이스와 함께 사용되어야 합니다.
함수형 인터페이스는 오직 하나의 추상 메서드만 정의된 인터페이스를 의미합니다.
함수형 인터페이스란?
함수형 인터페이스는 오직 하나의 추상 메서드만 정의된 인터페이스 입니다. 자바 8부터 @FunctionalInterface 어노테이션을 사용하여 함수형 인터페이스를 명시적으로 정의할 수 있습니다.
이 애너테이션은 해당 인터페이스가 함수형 인터페이스임을 표시하며, 만약 두 개 이상의 추상 메서드를 가지면 컴파일 오류를 발생시킵니다.
- 하나의 추상 메서드만 있어야 한다.
- 기본 메서드(default)와 정적 메서드(static)는 여러 개가 있을 수 있다.
예제: 함수형 인터페이스
interface MyFunctionalInterface1 {
void singleAbstractMethod(); // 하나의 추상 메서드
}
/////////////////////////////////////////////////////////////////////////////////////
interface MyFunctionalInterface2 {
void singleAbstractMethod(); // 하나의 추상 메서드
default void defaultMethod() {
System.out.println("This is a default method");
}
static void staticMethod() {
System.out.println("This is a static method");
}
}
//두개의 인터페이스 모두 함수형 인터페이스
//MyFunctionalInterface2는 기본 메서드와 정적 메서드를 가질 수 있지만,
//추상 메서드가 하나만 존재하기 때문에 함수형 인터페이스라고 할 수 있다.
//람다 표현 전 메서드
int add(int x, int y) {
return x + y;
}
// 위의 메서드를 람다 표현식을 이용해 아래와 같이 단축 가능 (메서드 반환 타입, 메서드 이름 생략)
(int x, int y) -> {
return x + y;
};
// 매개변수 타입도 생략 가능.
(x, y) -> {
return x + y;
};
// 함수에 리턴문 한줄만 있을 경우 더욱 더 단축 가능. (중괄호, return 생략)
(x, y) -> x + y;
적용 예제
interface Adder {
int add(int x, int y);
}
public class Main {
public static void main(String[] args) {
Adder adder = new Adder() {
@Override
public int add(int x, int y) {
return x + y;
}
};
System.out.println(adder.add(5, 3)); // 출력: 8
}
}
/////////////////////////////////////////////////////////////////////
interface Adder {
int add(int x, int y);
}
public class Main {
public static void main(String[] args) {
Adder adder = (x, y) -> x + y;
System.out.println(adder.add(5, 3)); // 출력: 8
}
}
List 예제
- 기본 익명 클래스 사용:
import java.util.Arrays;
import java.util.List;
public class Main {
public static void main(String[] args) {
List<String> list = Arrays.asList("apple", "banana", "cherry");
Consumer<String> consumer = new Consumer<String>() { //익명의 내부 클래스로 구현
@Override
public void accept(String s) {
System.out.print(s + " ");
}
};
list.forEach(consumer);
}
}
- 람다식 사용:
import java.util.Arrays;
import java.util.List;
public class Main {
public static void main(String[] args) {
List<String> list = Arrays.asList("apple", "banana", "cherry");
list.forEach( s -> System.out.print( s + " "));
//출력 : apple banana cherry
list.forEach(System.out::print);
//출력 : applebananacherry
//메서드 참조는 문자열을 포맷팅하거나 추가적인 처리를 직접적으로 할 수 없다
}
}
두개 이상의 매개변수 예제
1. BiFunction 예제
BiFunction<T, U, R> 인터페이스는 두 개의 매개변수(T, U)를 받고 결과(R)를 반환하는 함수형 인터페이스입니다.
예를 들어, 두 정수를 더하는 람다식을 작성할 수 있습니다.
import java.util.function.BiFunction;
public class Main {
public static void main(String[] args) {
// 두 개의 Integer를 받아서 Integer를 반환하는 BiFunction
//BiFunction<Integer, Integer, Integer> add = (x, y) -> x + y;
BiFunction<Integer, Integer, Integer> add = Integer::sum;
// 함수 호출
System.out.println("Sum: " + add.apply(5, 3)); // 출력: Sum: 8
}
}
2.1 BiConsumer 예제 1
BiConsumer<T, U> 인터페이스는 두 개의 매개변수를 받아 아무 결과도 반환하지 않는 함수형 인터페이스입니다.
예를 들어, 두 문자열을 합쳐서 출력하는 람다식을 작성할 수 있습니다.
import java.util.function.BiConsumer;
public class Main {
public static void main(String[] args) {
// 두 개의 String을 받아서 콘솔에 출력하는 BiConsumer
BiConsumer<String, String> printConcatenation = (s1, s2) -> System.out.println(s1 + s2);
// 함수 호출
printConcatenation.accept("Hello, ", "World!"); // 출력: Hello, World!
////////////////////////////////////////////////////////////////////////////////////////////////
//메서드 참조는 문자열을 포맷팅하거나 추가적인 처리를 직접적으로 할 수 없다.
//그래도 하려면 아래 코드
Consumer<String> print = System.out::println;
String s1 = "Hello, ";
String s2 = "World!";
print.accept(s1 + s2); // 출력: Hello, World!
}
}
2.1 BiConsumer 예제 2
import java.util.HashMap;
import java.util.Map;
import java.util.function.BiConsumer;
public class Main {
public static void main(String[] args) {
// Map 생성 및 데이터 추가
Map<String, String> map = new HashMap<>();
map.put("a", "ant");
map.put("b", "bee");
map.put("c", "cow");
// BiConsumer를 사용하여 Map의 키와 값을 출력
BiConsumer<String, String> printEntry = (key, value) ->
System.out.println("Key: " + key + ", Value: " + value);
map.forEach(printEntry);
//더 간결한 람다식
map.forEach((key, value) -> System.out.println("Key: " + key + ", Value: " + value));
});
}
}
공부할때 List의 타입을 Object 로 두고 테스트를 진행했지만, 람다식을 사용할때는 타입에 관계없이 타입에 따라
람다식의 매개변수 타입이 자동으로 추론됩니다.
가장 일반적인 함수형 인터페이스는 Runnable, Callable, Consumer, Supplier, Function, Predicate 등이 있습니다.
그 외 함수 https://docs.oracle.com/javase/8/docs/api/java/util/function/package-summary.html