JAVA 람다(lambda)
lambda란?
함수형 프로그래밍에서 사용되는 개념입니다. 익명(Anonymous) 함수라고 불립니다.
lambda 특징
1. 추론이 가능한 코드는 제거해 코드가 간결하다 -> 가독성 향상
2. 전달되는 매개변수에 따라서 행위가 결정된다.
3. 람다식 표현 = (파라미터) -> {몸체} 몸체는 return문이 없는 단 일행 일면, {} 생략 가능
코드로 예시를 보겠습니다.
interface Calculator{ // 추상 메소드가 하나인 인터페이스
void operation(int a, int b);
}
public class Main {
public static void main(String[] args) throws IOException {
Calculator calculator = new Calculator() { // 람다를 사용하지 않은 형태
@Override
public void operation(int a, int b) {
System.out.println(a+b);
}
};
Calculator lambdaCalculator = (a,b) -> { // 추상 메소드를 람다식으로 표현
System.out.println(a+b);
};
}
}
lambda와 함수형 인터페이스
이미 제작되어 있는 함수형 인터페이스들이 있습니다. 해당 인터페이스를 하나씩 살펴보겠습니다.
Comparator
정렬을 하는데 이용됩니다. Comparator의 형태입니다.
해당 부분을 lambda를 이용해서 구현해보겠습니다.
public interface Comparator<T> {
int compare(T o1, T o2);
}
public class Main {
public static void main(String[] args) throws IOException {
List<Integer> list = new ArrayList<>();
list.add(1);
list.add(3);
list.add(5);
list.add(4);
list.add(2);
Collections.sort(list, (a,b) -> { // comareTo(T o1, T o2)에 a와 b가 매개변수로 전달됩니다.
return a-b; // 양수일 경우 바꾸므로 해당 정렬은 오름차순입니다.
});
for(Integer now: list){
System.out.println(now);
}
// 출력
// 1
// 2
// 3
// 4
// 5
Collections.sort(list, (a,b)-> {// comareTo(T o1, T o2)에 a와 b가 매개변수로 전달됩니다.
return -(a-b); //양수일 경우 바꾸므로 해당 정렬은 내림차순입니다.
});
for(Integer now: list){
System.out.println(now);
}
// 출력
// 5
// 4
// 3
// 2
// 1
}
}
매개 변수가 있고, 반환하는 람다식
interface Calculator{
int cal(int a, int b);
}
public class Main {
public static void main(String[] args) throws IOException {
Calculator c;
c = (a,b) -> { // a와 b를 매개변수로 넘깁니다.
return a+b;
};
int cal = c.cal(1, 2);
System.out.println(cal); // 3 출력
c = (a,b) ->{
return a-b;
};
cal = c.cal(1,2);
System.out.println(cal); // -1 출력
c = new Calculator() { // 람다식을 사용하지 않고, Calculator의 cal 함수를 구현한 것입니다. 람다와 같은 결과를 냅니다.
@Override
public int cal(int a, int b) {
return a-b;
}
};
cal = c.cal(1,2);
System.out.println(cal); // -1 출력
}
}
@FunctionalInterface
interface에 하나의 추상 메서드만 존재해야 람다식으로 표현이 가능합니다. @FunctionalInterface를 interface에 붙여 조기 검증이 가능합니다.
- 추상 메서드가 2개 이상이므로 @FunctioanlInterface에서 컴파일 오류를 확인할 수 있습니다.
- 혹여나 @FunctionalInterface를 붙이지 않아 검증이 안돼도, 람다식에서 컴파일 오류를 확인할 수 있습니다.
단 허용되는 메서드도 있습니다.
- defalut 메소드
- static 메소드
자바에 정의되어 있는 함수형 인터페이스
자바에서 표준으로 정의하고 있는 함수형 인터페이스들이 있습니다. 하나씩 알아보겠습니다.
Predicate
public interface Predicate<T> {
boolean test(T t);
}
전달된 인자를 대상으로 true, false 판단합니다.
짝수와 홀수의 합을 출력하는 예시를 보겠습니다.
public class Main {
public static void main(String[] args) throws IOException {
List<Integer> list = new ArrayList<>();
list.add(1);
list.add(2);
list.add(3);
list.add(4);
list.add(5);
list.add(6);
list.add(7);
int evenResult = returnOddSumOrEvenSum(a -> a % 2 == 0, list); // 짝수를 판별합니다.
System.out.println(evenResult); // 2+4+6 -> 12 출력
int oddResult = returnOddSumOrEvenSum(a -> a%2==1, list);
System.out.println(oddResult); // 1+3+5+7 -> 16 출력
}
private static int returnOddSumOrEvenSum(Predicate<Integer> p, List<Integer> list){
int sum=0;
for(Integer now: list){
if(p.test(now)){
sum+=now;
}
}
return sum;
}
}
- a -> (a에 대한 판별식) 매개변수로 보낸 것을 판별하는 식을 통해 boolean을 반환합니다.
Supplier
단순히 무언가를 반환할 때 사용됩니다. 매개변수로 넘기는 것이 없습니다.
public interface Supplier<T> {
T get();
}
난수를 생성하고 반환하여 출력하는 예시를 보겠습니다.
public class Main {
public static void main(String[] args) throws IOException {
List<Integer> list = new ArrayList<>();
list = randomList(() -> {
Random random = new Random(); // T get()을 람다식으로 구현
return random.nextInt(10); // 10이하의 랜덤수 생성
}, list);
for(Integer now: list){
System.out.println(now); // 만들어진 10개의 수 출력
}
}
private static List<Integer> randomList(Supplier<Integer> s, List<Integer> list){
for(int i=0; i<10; i++){
Integer integer = s.get();
list.add(integer);
}
return list;
}
}
- T get()을 매개변수 없이 반환하는 람다식을 표현하고, 랜덤 수를 생성하는 것을 볼 수 있습니다.
Consumer
전달된 인자를 기반으로 반환 이외의 다른 실행을 할 수 있습니다.
public interface Consumer<T> {
void accept(T t);
}
난수를 생성하고 출력하는 예시를 보겠습니다.
public class Main {
public static void main(String[] args) throws IOException {
List<Integer> list = new ArrayList<>();
Random random = new Random();
Consumer<Integer> c = (a) -> { //void accept(T o) 람다식으로 표현
System.out.println(a);
};
for (int i = 0; i < 10; i++) {
int num = random.nextInt(); // 난수 생성
c.accept(num); // 출력
}
}
}
- void accept(T o)를 구현하지만, 반환 없이 출력을 수행합니다.
Function
매개 변수와 반환 값이 모두 존재하며, 2번째 매개변수 형태를 반환합니다.
public interface Function<T, R> {
R apply(T t);
}
문자열이 들어오고, 문자열의 길이를 반환하는 Function을 만들겠습니다.
public class Main {
public static void main(String[] args) throws IOException {
List<String> list = new ArrayList<>();
list.add("robot");
list.add("cat");
list.add("university");
Function<String, Integer> f = a -> { // String인 a가 들어오고 a의 길이를 반환합니다.
return a.length();
};
for(String now: list){
Integer length = f.apply(now);
System.out.println(length); // 5, 3, 10 출력됩니다.
}
}
}
- Integer apply(String s)의 형태로 진행됩니다.
정리
람다와 람다 표현식을 이용하여, 코드의 길이를 줄였습니다. 이는 코드의 가독성을 올려줍니다.
지금까지 람다와 람다 표현식을 알아봤습니다. 틀린 부분에 대해서 지적해주시면 감사합니다.
'JAVA' 카테고리의 다른 글
JAVA Enum (0) | 2022.02.24 |
---|---|
JAVA Stream (0) | 2022.02.23 |
JAVA Optional<T> (0) | 2022.02.23 |
JAVA Comparable And Comparator (0) | 2022.02.21 |
Java 제네릭(Generic) (0) | 2022.02.20 |
댓글
이 글 공유하기
다른 글
-
JAVA Stream
JAVA Stream
2022.02.23 -
JAVA Optional<T>
JAVA Optional<T>
2022.02.23 -
JAVA Comparable And Comparator
JAVA Comparable And Comparator
2022.02.21 -
Java 제네릭(Generic)
Java 제네릭(Generic)
2022.02.20