0. 개요
- 자바는 OOP 언어이다.
- 빅데이터 처리의 요구가 늘어나며 함수형 언어의 기능에대한 필요성이 증대했다.
1. 람다식이란
- 함수(메서드)를 간단한 식으로 표현하는 익명함수
- 익명함수란 이름이 없는 함수이다.
- 함수와 메서드는 근본적으로 동일하나 함수는 일바적 용어인 반면 메서드는 객체지향 개념의 용어이다.
- 함수는 클래스에 독립적이나, 메서드는 클래스에 종속적이다. 자바의 모든 함수는 클래스 내에서 선언되므로 모든 함수는 메서드라 지칭한다.
// 메서드
int max(int a, int b) {
return a > b ? a : b;
}
// 람다식
(a, b) -> a > b ? a : b;
2. 람다식의 특징
- 메서드의 이름과 반환타입을 제거하고 화살표(->)를 블록 앞에 추가한다.
- 반환값이 있을 경우 return이나 세미콜론(;)를 생략한 채로 식이나 값만을 적는다.
- 매개변수의 타입이 추론 가능할 경우 생략 가능하다. (대부분의 경우 생략 가능하다.)
- 매개변수가 하나이고 타입이 없는 경우 괄호 ()가 생략 가능하다.
a -> a * a // OK
int a -> a * a // 에러
(int a) -> a * a // OK
- 블록 안의 문장이 하나인 경우 괄호를 생략할 수 있다. 또한 이 때, 식의 끝에 세미콜론을 붙이지 않는다.
(int i) -> {
System.out.println(i);
}
(int i) -> System.out.println(i) // 문장이 하나인 경우 {} 생략, ; 생략
- 하나뿐인 문장이 return문인 경우 괄호 {} 생략 불가
(int a, int b) -> ( return a > b ? a : b; ) // OK
(int a, int b) -> return a > b ? a : b // error
- 람다식의 예
(a, b) -> a > b ? a : b
(name, i) -> System.out.println(name + "=" + i)
x -> x * x
() -> (int) Math.random() * 6
- 자바에서 람다식은 익명 함수가 아닌 익명 객체이다. 자바의 함수는 모두 클래스에 종속된 메서드이기 때문에 람다식 역시도 익명 함수가 아닌 익명 객체이다. 즉, 익명함수는 객체이기 때문에 참조변수가 필요하다.
// 자바의 람다식은 익명 클래스와 동등하다.
(a, b) -> a > b ? a : b
// 익명 클래스 : 객체의 선언과 생성을 동시에 한다.
new Object() {
int max(int a, int b) {
return a > b ? a : b;
}
}
- 자바 람다식의 참조변수타입은 Object가 될 수 있으나 호출이 불가능하다.
Object obj = (a, b) -> a > b ? a : b // 에러 -> 람다식은 익명객체이다.
// 익명객체를 생성하고 호출해 보았다.
Object obj = new Object() {
int max(int a, int b) {
return a > b ? a : b;
}
};
int value = obj.max(3, 5); // 에러 -> 함수형 인터페이스가 필요하다.
3. 함수형 인터페이스
- 함수형 인터페이스란? : 단 하나의 추상 메서드만 선언된 인터페이스
- 기본적으로 추상 메서드는 인터페이스에 선언된 메서드이다. 만약 이 추상 메서드가 오직 한개라면 함수형 인터페이스라고 한다.
@FunctionalInterface // 어노테이션을 작성한 경우 컴파일러가 올바르게 작성되었는지 확인한다.
interface MyFunction {
public abstract int max(int a, int b); // public abstract는 생략이 가능하다. 인터페이스의 추상 메서드는 반드시 public이다.
}
// 익명 클래스를 통해 함수형 인터페이스의 max 메서드를 구현한다.
// 이 때, 클래스의 선언과 객체의 생성이 동시에 이루어진다.
Myfunction f = new MyFunction() {
@Override // 오버라이딩의 규칙에 따라 접근제어자는 좁게 못바꾼다. 반드시 public이다.
public int max(int a, int b) {
return a > b ? a : b;
}
};
int value = f.max(3, 5); // OK. MyFunction에 max()가 있으며 호출할 수 있다.
- 익명 객체에서와 마찬가지로 람다식을 함수형 인터페이스 타입으로 참조할 수 있다. 단, 함수형 인터페이스의 메서드와 람다식의 매개변수 개수, 반환타입이 일치해야 한다.
MyFunction f = (a, b) -> a > b ? a : b;
int value = f.max(3, 5); // 람다식이 호출됨
- 즉 람다식(익명 객체)을 호출하기 위해 필요한 참조 변수의 타입은 함수형 인터페이스이다.
- 람다식은 익명객체를 대신한다. 아래는 메서드의 매개 변수로 함수형 인터페이스인 Comparator를 요구하고 있다. 함수형 인터페이스는 익명객체나 람다식을 참조한다.
List<String> list = Arrays.asList("abc", "aaa", "bbb", "Ddd", "aaa");
Collections.sort(list, new Comparator<String>() {
@Override
public int compare(String s1, String s2) {
return s2.compareTo(s1);
}
});
Collections.sort(list, (s1, s2) -> s2.compareTo(s1));
- 함수형 인터페이스 타입을 매개 변수로 가질 수 있다.
- 함수형 인터페이스 타입을 반환할 수 있다. (람다식을 반환한다.)
import java.io.*;
class Main {
public static void main(String[] args) throws IOException {
MyFunction f1 = () -> System.out.println("f1.run");
MyFunction f2 = new MyFunction() {
@Override
public void run() {
System.out.println("f2.run");
}
};
MyFunction f3 = getMyFunction();
f1.run();
f2.run();
f3.run();
execute(f1);
execute(() -> System.out.println("run"));
}
static MyFunction getMyFunction() {
return () -> System.out.println("f3.run");
}
static void execute(MyFunction f){
f.run();
}
}
@FunctionalInterface
interface MyFunction {
void run();
}
'프로그래밍언어 > Java' 카테고리의 다른 글
Java Lambda Expression, 자바8 람다식 (0) | 2023.06.21 |
---|---|
Java Collection Framework (JCF) (0) | 2023.06.21 |
가변객체와 불변객체 (0) | 2023.05.23 |
자바 어노테이션 (0) | 2023.05.21 |
[Java] Optional이 모길래??? (0) | 2023.04.13 |