람다함수
람다함수는 메소드를 하나의 식(Expression)으로 표현하는 것으로 익명함수(Anonymous function)를 생성 한다.
함수형 프로그래밍을 하고자 하며 나왔다고 한다.
자바에서는 메소드 혼자 선언해서 쓸 수 없다. 무조건 class의 구성멤버로 선언되어야 한다.
람다식으로 생성되는 것은 메소드 자체가 아니라 실행문(메소드)를 가진 객체이다. 이 객체는 일반적인 객체가 아닌 함수형 인터페이스를 구현한 익명 구현 객체이다.
람다의 특징
1. 익명함수
- 함수 이름이 없다. 익명함수는 일급객체(first class citizen)이다.
2. 커링
- 두개 이상의 입력이 있는 함수는 최종적으로 1개의 입력만 받는 람다로 단순화 할 수 있다.
람다의 표현식
1. 화살표로 표시한다.
2. 몸체가 한줄이면 { } 생략 가능
3. 몸체에 return만 있으면 return생략 가능
(x, y) -> {
// do something
}
() -> {return 1;}
() -> 1
함수형 인터페이스
람다는 함수형 인터페이스를 구현한다.
함수형 인터페이스란,
메소드가 하나밖에 없는 인터페이스를 말한다.
이를 명시적으로 선언하기 위해 @FunctionalInterface를 써줄 수 있다.
@FunctionalInterface를 써주면 메소드가 여러개일경우 오류를 내준다.
@FunctionalInterface
public interface Calculator {
int calc(int n);
}
Calculator를 객체화 할 때 두가지 방법을 쓸 수 있다.
1. 이전까지 쓰던데로, implements를 통해 class 생성
2. Lambda를 이용해 익명 클래스로 생성
이전에는 아래와 같이 사용했다. 인터페이스의 추상메소드를 생성과 동시에 구현할 수 있다. (익명객체 참고)
package lambda;
public class Main {
public static void main(String[] args) {
// 인터페이스의 추상메소드를 생성과 동시에
// { @Override ... } 를 통해 구현할 수 있다.
Calculator cal = new Calculator() {
@Override
public int calc(int n) {
return 0;
}
};
}
}
람다는 이것을 간단하게 나타낼 수 있다.
package lambda;
public class Main {
public static void main(String[] args) {
int n=2;
Calculator cal2 = num -> num + 1;
// 타입을 추론할 수 있으므로 생략 가능
System.out.println(cal2.calc(n));
// 3
Calculator cal3 = num -> num - 1;
System.out.println(cal3.calc(n));
// 1
}
}
코드가 훨씬 깔끔해 진 것을 볼 수 있다.
람다식은 위와 같이 사용하기 때문에 타겟이 되는 인터페이스에 추상 메소드가 반드시 하나인 Functional Interface여야 한다. 추상메소드가 2개 이상이면, 해당 람다식이 어떤 메소드를 구현한 것인지 알 수 없게 되기 때문이다.
Method Reference
이미 구현되어있는 메소드를 참조해 불필요한 매개변수를 제거한다.
람다식을 아래와 같이 간추릴 수 있다.
package lambda;
public interface Operator {
public int run(int x, int y);
}
package lambda;
public class Main {
public static void main(String[] args) {
int num1 = 1, num2 = 2;
Operator op1 = (x, y) -> Math.max(x, y);
System.out.println(op1.run(num1, num2));
Operator op2 = Math::max;
System.out.println(op1.run(num1, num2));
}
}
메소드 레퍼런스에는 4가지 방법이 있다.
1. 정적 메소드 참조
2. 인스턴스 메소드 참조
3. 생성자 참조
위의 코드는 1번의 방법이라고 할 수 있다.
2번, 3번은 아래와 같다.
// 2
(x,y) -> 인스턴스.메소드(x,y)
인스턴스::메소드
//3
(객체) -> new 객체
객체::new
java.util.function 패키지
지금까지와 같이 interface를 구현할 수도 있지만, 이미 구현되어있는 interface들이 많이 있다. 이것만 사용해도 거의 모든 상황을 커버할 수 있다.
Predicate, Consumer, Supplier, Function<T,R>, Comparator, Runnable, Callble등이 있다. 더 있으니 java8 api를 뒤져보자.
package lambda.predicate;
import java.util.function.Consumer;
import java.util.function.Predicate;
public class Ex {
public static void main(String[] args)
{
// Predicate는 무언가 비교할 때 쓴다.
// test메소드는 Boolean을 반환한다.
Predicate<Integer> lesserthan = i -> (i < 10);
Boolean res = lesserthan.test(3);
System.out.println(res);
// Consumer는 말그대로 소비만 한다.
// accept메소드는 리턴 타입 void이다.
Consumer<Integer> print = i -> System.out.println(i * 10);
print.accept(7);
}
}
참고
익명객체 https://limkydev.tistory.com/226
Predicate https://www.geeksforgeeks.org/java-8-predicate-with-examples/
'java' 카테고리의 다른 글
[eclipse] unable to start within 45 seconds 오류 해결 (0) | 2022.07.20 |
---|---|
[Java] POI 오류, "허용되는 글꼴 수가 초과되어 이 파일에 글꼴 서식이 제대로 적용되지 않을 수 있습니다." (2) | 2022.06.16 |
[Java] JDK 설치하기 (0) | 2022.02.26 |
[spring] @RequestBody, @ResponseBody 란, 스프링 데이터 주고받기 (0) | 2021.11.30 |
[java] 컬렉션과 제네릭에 대해 알아보기 (0) | 2021.11.03 |