❗️ 함수형 프로그래밍 이해도를 높이고, Java 람다식 사용을 할 수 있다.
For-loop 사용 시, 가동성 🆙
Stream API
같은 함수형 도구 도입Scala
, Kotlin
, Python
등은 함수형 지원 강함// 기존 방식
new Thread(new Runnable() {
@Override
public void run() {
System.out.println("스레드 실행!");
}
}).start();
// 람다식 방식
new Thread(() -> System.out.println("스레드 실행!")).start();
👉 불필요한 익명 클래스 코드가 사라지고 깔끔해짐.
import java.util.Arrays;
import java.util.List;
public class Main {
public static void main(String[] args) {
List<String> names = Arrays.asList("정잉이", "철수", "영희", "민수");
// 기존 방식: for문
for (String name : names) {
if (name.startsWith("정")) {
System.out.println(name);
}
}
// 함수형 방식: Stream
names.stream()
.filter(n -> n.startsWith("정"))
.forEach(System.out::println);
}
}
👉 filter
, forEach
같은 고차 함수 덕분에 무엇을 할지만 표현 가능.
Optional<String> name = Optional.ofNullable(null);
// 기존 방식
if (name.isPresent()) {
System.out.println(name.get());
}
// 함수형 방식
name.ifPresent(System.out::println);
👉 null
체크 보일러플레이트 줄이고 안전한 코드 작성 가능.
✅ 간단한 함수 표현 + 객체 생성
람다식의 기본 형태는:
(매개변수) -> { 실행문 }
() -> System.out.println("Hello Lambda!");
x -> System.out.println(x)
👉 괄호 ()
생략 가능 (매개변수 1개일 때만)
(a, b) -> a + b
(x, y) -> {
int sum = x + y;
return sum;
}
자바에서 람다식은 반드시 함수형 인터페이스(추상 메서드가 딱 1개 있는 인터페이스)와 함께 써야 함.
// Java 람다 인터페이스 정의
@FunctionalInterface
interface MyFunction {
int run(int x, int y);
}
// 람다 구현 및 실행
public class Main {
public static void main(String[] args) {
// 람다식으로 인터페이스 구현
MyFunction f = (a, b) -> a + b;
System.out.println(f.run(3, 5)); // 8
}
}
@FunctionalInterface
public interface StringNum {
void printString(String str, int myInt);
}
StringNum stringNum1 = (str, myInt) -> System.out.printf("%s 와 %d 입니다. \n", str, myInt);
StringNum stringNum2 = (str, myInt) -> {
for(int i = 0; i < myInt; i++) {
System.out.println("두번 쨰: " + str);
}
};
[기존 방식]
int max(int a, int b) {
return a > b ? a: b;
}
[람다식]
(int a, int b) -> {
return a > b ? a : b;
}
👉 메서드의 이름과 반환타입을 제거하고 ->
를 블록 {}
앞에 추가한다.
(int a, int b) -> {
return a > b ? a : b;
}
➡️ (int a, int b) -> a > b ? a : b
👉 반환값이 있는 경우, 식이나 값만 적고 return문 생략 가능(끝에 ;
안 붙임)
(int a, int b) -> a > b > a : b
➡️ (a, b) -> a > b ? a : b
👉 매개변수의 타입이 추론 가능하면 생략가능(대부분의 경우 생략가능)
👉 인자가 하나면 ()
생략
public class Main {
public static void main(String[] args) {
// add (람다식) 전달
int result1 = calculate(5, 3, (a, b) -> a + b);
System.out.println("덧셈 결과: " + result1);
// multiply (람다식) 전달
int result2 = calculate(5, 3, (a, b) -> a * b);
System.out.println("곱셈 결과: " + result2);
}
// 함수형 인터페이스 정의 (직접 정의)
interface Operation {
int apply(int a, int b);
}
// 메서드 인자로 함수(Operation) 받기
public static int calculate(int x, int y, Operation op) {
return op.apply(x, y);
}
}
덧셈 결과: 8
곱셈 결과: 15
👉 여기서 (a, b) -> a + b
같은 람다식이 바로 인자로 전달되는 함수이다.
public class Main {
public static void main(String[] args) {
repeat(3, i -> System.out.println(i + "번째 실행!"));
}
interface Task {
void run(int i);
}
public static void repeat(int n, Task task) {
for (int i = 1; i <= n; i++) {
task.run(i);
}
}
}
1번째 실행!
2번째 실행!
3번째 실행!
public class Main {
public static void main(String[] args) {
// Integer 타입 연산
int sum = operate(5, 3, (a, b) -> a + b);
System.out.println("덧셈 결과: " + sum);
// String 타입 연산
String result = operate("Hello", "World", (a, b) -> a + " " + b);
System.out.println("문자열 합치기: " + result);
}
// 제너릭 함수형 인터페이스
interface Operation<T> {
T apply(T a, T b);
}
// 제너릭 메서드
public static <T> T operate(T x, T y, Operation<T> op) {
return op.apply(x, y);
}
}
덧셈 결과: 8
문자열 합치기: Hello World
👉 여기서 핵심은 Operation<T>
와 operate
메서드가 제너릭이라,
Integer
, String
, Double
… 어떤 타입에도 람다를 적용할 수 있다는 것이다.
Stream API
랑 람다를 같이 쓰면, 데이터 처리 코드가 확 준다.List<String> names = Arrays.asList("Kim", "Lee", "Park", "Choi");
// "P"로 시작하는 이름만 추출
List<String> result = names.stream()
.filter(n -> n.startsWith("P"))
.map(String::toUpperCase)
.toList();
System.out.println(result); // [PARK]
👉 람다 덕분에 반복문, if문 다 줄어들고 “데이터 처리 파이프라인”처럼 읽힘.
Comparator
객체를 직접 구현할 필요 없이 람다로 바로 작성.List<String> list = Arrays.asList("banana", "apple", "cherry");
// 기존
Collections.sort(list, new Comparator<String>() {
@Override
public int compare(String a, String b) {
return a.compareTo(b);
}
});
// 람다
list.sort((a, b) -> a.compareTo(b));
Runnable
, Callable
을 간단히 작성할 때 유용하다.// 기존
new Thread(new Runnable() {
@Override
public void run() {
System.out.println("작업 실행!");
}
}).start();
// 람다
new Thread(() -> System.out.println("작업 실행!")).start();
Optional<String> name = Optional.ofNullable(null);
// 값이 없으면 Supplier 실행
String result = name.orElseGet(() -> "기본값");
System.out.println(result); // 기본값
람다는 실무에서 주로:
🔹 Stream API
(데이터 필터링, 매핑, 집계)
🔹 정렬 (Comparator
간단화)
🔹 이벤트/콜백 처리 (UI, 스레드)
🔹 Optional
(널 처리)
🔹 전략 패턴/콜백 패턴 같은 디자인 패턴 단축
👉 한마디로, “코드 짧고 직관적으로 만들고 싶을 때” 람다가 많이 쓰인다.