Programming/Java

[Java9 프로그래밍] 12. 람다 표현식

빠모스 2020. 3. 21. 17:58
반응형

함수형 인터페이스

Comparator 인터페이스

<예시 1>

int compare(T first, T second);
// T는 어떠한 타입이 와도 된다는 이야기.

 

Runnable 인터페이스

<예시 2>

void run();
// thread에서 많이 사용한다. 

 

 

사용자 인터페이스 콜백

<예시 3>

void handle(ActionEvent e);

 

 

함수형 인터페이스란?

추상 메소드 하나만 포함하는 인터페이스

 

 

Comparator 인터페이스 예제

 

<예시 1> Comparator 인터페이스를 구현한 클래스

class LengthComparator implements Comparator<String> {

	public int compare(String first, String second) {
		return first.length() - second.length();
	}
}

=> 자바에서는 comparator 인터페이스를 이용해 ‘정렬’을 한다.

위의 예는 자바8 이전에 Comparator 인터페이스를 구현했던 방식이다.

Comparator 인터페이스 내의 compare라는 메소드는 추상메소드이기 때문에 LengthComparator가 오버라이딩해서 compare을 재정의해야한다.

두 개의 파라미터를 비교해서 앞에 것이 크면 양수를 리턴하고, 뒤에것이 크면 음수를, 같으면 0을 리턴한다.

 

 

Comparator 구현 객체를 사용한 예제

<예시 2>

String[] friends = { “kim”, “lee”, “park”, “hwang” };

Arrays.sort(friends, new LengthComparator());

=> sort 메소드는 첫 번째 파라미터로 배열을, 두 번째는 실제 comparator를 구현한 객체를 받는다. 

 

 

 

람다표현식

 

- 함수를 아주 짧게 표현한 것으로 보아도 좋다.

 

  • 나중에 실행할 수 있게 전달하는 코드 블럭 (로직, 알고리즘을 포함하는 재사용 가능한 블럭)
  • Array.sort에 비교 메소드 전달 등
  • 자바 8 이전에는 자바는 함수 타입이 없으므로, 함수를 메소드 파라미터로 전달할 수 없었다.
  • 함수(로직)를 메소드로 전달하기 위해서 제공하는 새로운 문법(Java 8)

<예시>

String[] friends = { “kim”, “lee”, “park”, “hwang” };
LengthComparator lengthComparator = (String first, String second) -> first.length() - second.length();
//=> 람다표현식. 함수를 변수에 담는다.
// 왼쪽엔 변수, 오른쪽은 로직이 온다.

Arrays.sort(friends, lengthComparator);
//=> sort의 파라미터로 배열과 함수(로직)을 넣어줄 수 있게 됨. 그 전에는 배열과 객체를 넣어줬음.

자바에서 함수형 인터페이스는 모두 람다 표현식으로 바꿀 수 있다. 즉, 추상 메소드를 하나만 포함하는 인터페이스는 이 추상 메소드를 람다 표현식으로 표현해서 바로 파라미터로 넘길 수 있다.

 

 

람다 표현식 사례

람다 표현식은 함수형 인터페이스와 호환된다.

 

예제1) Array.sort 메소드

두 번째 파라미터로 Comparator 인터페이스의 인스턴스가 필요

Array.sort(words, (first, second) -> first.length() - second.length());

 

// words는 배열. 이 배열을 두번째 파라미터로 람다식을 넘겨준다. 

// first와 second의 타입은 String인데 두 파라미터의 타입이 같으면 String을 생략해도 된다. JVM에 타입을 추론하는 기능이 포함되있다.

 

 

예제2) ArrayList.removeIf 메소드

Predicate 인터페이스의 인스턴스가 필요

list.removeIf(e -> e == null);

 

// removeIf는 파라미터로 Predicate 인터페이스를 받는다. 이 인터페이스는 함수형 인터페이스이기 때문에 람다식으로 바꿀 수 있다. 파라미터 e가 null이면 True를, 아니면 False를 반환한다. True면 remove 한다.

기존에는 반복문으로 리스트 내의 원소 하나하나 다 접근해서 null인지 확인해야 했으나 함수형 프로그래밍이 되면서 전체 리스트 엘레먼트에 이 함수를 적용하는 것이다.

 

 

함수형 인터페이스 

 

  • Predicate : 특정한 데이터를 가지고 불리안을 리턴함.
  • Consumer : 데이터를 확인해서 소모하고 리턴값은 없다.
  • Fucntion : T를 R로 바꿔줌. 데이터 타입을 바꿔준다.
  • Supplier : 뭔가를 하나 만들어서 리턴.
  • BinaryOperator : 두개의 파라미터를 받아 같은 타입으로 반환.

 

ThinkPoint

자바는 자바8에서 람다식을 추가하였다. 자바에서 람다식의 의미와 장단점은?

람다식은 간단히 말해 함수를 변수처럼 사용할 수 있는 개념이다.

JDK8 이전의 자바에는 ‘메소드’라는 함수 형태가 존재하지만 객체(혹은 클래스)를 통해서만 접근이 가능하고, 메소드 그 차제를 변수로 사용하지는 못해왔다.

JDK8에서는 함수를 변수처럼 사용할 수 있기 때문에, 파라미터로 다른 메소드의 인자로 전달할 수 있고, 리턴값으로 함수를 받을수도 있다.

자바람다식은 사실 완벽한 함수형 프로그래밍방식이라고 할수는 없다.

이유는 자바 람다식은 함수형에 대해서 새로 정의한 것이 아니고, 기존에 존재하는 interface의 형태를 빌어 람다식을 표현하기 때문이다. 

그러므로 함수형 프로그래밍의 장점을 완전히 가지지는 못한다.

그럼으로써 생기는 장단점이 존재한다.

 

 

실습 코드

1. Comparator 예제 방법 1 - 함수형 인터페이스 객체화, 파라미터로 넘겨주기

package com.acompany.lambda;

import java.util.Arrays;
import java.util.Comparator;

//// Comparator 예제 방법 1 - 함수형 인터페이스 객체화, 파라미터로 넘겨줌 ////
public class LambdaTest2 {
    public static void main(String[] args) {
        String[] animals = {"cat", "hippo", "giraffe", "elephant", "monkey"};
        AnimalComparator comparator = new AnimalComparator();
        // 파라미터로 (배열, 정렬 로직 객)
        Arrays.sort(animals, comparator);

        for (String item : animals){
            System.out.println(item);
        }
    }
    // 자바는 함수를 파라미터로 넣을 수 없기 때문에 함수를 포함한 객체를 만들어줘야 함
    static class AnimalComparator implements Comparator<String>{
        // Comparator 인터페이스의 추상메소드를 구현해줘야 함.
        @Override // 함수형 인터페이스를 객체화하여 파라미터로 넘겨준다.
        public int compare(String o1, String o2) {
            return o1.length() - o2.length();
        }
    }
}

 

2. Comparator 예제 방법 2  - 단순화시키기

Arrays.sort에서 바로 객체를 생성시켜 오버라이딩할수도 있다.

package com.acompany.lambda;

import java.util.Arrays;
import java.util.Comparator;
//// Comparator 예제 방법 2 ////
public class LambdaTest3 {
    public static void main(String[] args) {
        String[] animals = {"cat", "hippo", "giraffe", "elephant", "monkey"};
        Arrays.sort(animals, new Comparator<String>() {
            @Override
            public int compare(String o1, String o2) {
                return o1.length() - o2.length();
            }
        });

        for (String item : animals){
            System.out.println(item);
        }
    }
}

 

3. Comparator을 람다식으로 표현하기

package com.acompany.lambda;

import java.util.Arrays;
import java.util.Comparator;
//// Comparator을 람다식으로 표현하기 ////
public class LambdaTest {
    public static void main(String[] args) {
        String[] animals = {"cat", "hippo", "giraffe", "elephant", "monkey"};
        Arrays.sort(animals, (o1, o2) -> o1.length()-o2.length());
        // 파라미터 목록 -> 적용할 로직
        // 두 파라미터의 타입이 같을땐 타입을 안써줘도 된다.
        for (String item : animals){
            System.out.println(item);
        }
    }
}

 

4. 리스트를 Predicate 인터페이스로 정렬해보기 1

package com.acompany.lambda;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.function.Predicate;

//// 리스트로 정렬해보기 1 ////
public class LambdaTestList {
    public static void main(String[] args) {
        List<String> animals = new ArrayList<>(
                Arrays.asList("cat", "hippo", "a", "giraffe", "elephant", "monkey", "")
        );

        // 글자가 하나이거나 없는 요소를 제거해보자. 원래는 반복문을 쓰지만 람다를 이용해보자.
        AnimalPredicate animalPredicate = new AnimalPredicate();
        animals.removeIf(animalPredicate);

        System.out.println(animals);

    }

    static class AnimalPredicate implements Predicate<String>{
        @Override
        public boolean test(String s) {
            return s.length()<2; // 2글자 미만인 문자열은 True가 반환되며 제거됨.
        }
    }
}

 

5. 리스트를 Predicate 인터페이스로 정렬해보기 2 - 단순화시키기

package com.acompany.lambda;

import java.sql.SQLOutput;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.function.Predicate;

//// 리스트로 정렬해보기 2 ////
public class LambdaTestList2 {
    public static void main(String[] args) {
        List<String> animals = new ArrayList<>(
                Arrays.asList("cat", "hippo", "a", "giraffe", "elephant", "monkey", "")
        );
        animals.removeIf(new Predicate<String>() {
            @Override
            public boolean test(String s) {
                return s.length() < 2;
            }
        });
        System.out.println(animals);
    }
}

 

6. 리스트를 람다로 정렬시키기

package com.acompany.lambda;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

//// 리스트 정렬을 람다로 표현해보기 ////
public class LambdaTestList3 {
    public static void main(String[] args) {
        List<String> animals = new ArrayList<>(
                Arrays.asList("cat", "hippo", "a", "giraffe", "elephant", "monkey", "")
        );
        animals.removeIf(s -> s.length() < 2);

        System.out.println(animals);

    }

}
반응형