본문 바로가기

Java/Java8

(JAVA8) 람다식 (2)

함수형 인터페이스의 사용

줄곧 말하지만 함수형 인터페이스는 오직 하나의 추상 메서드 만을 갖는다.

함수형 인터페이스 내부의 추상 메서드는 : 함수 디스크립터라고 불린다.

 

이전에는  우리가 함수형 인터페이스를 직접 만들어 사용하였지만 자바에서 미리 만들어놓은 함수형 인터페이스들이 존재한다.

 

 

1. Predicate

추상메서드 이외에도 여러가지 디폴트메서드가 존재한다.

활용

list와 Predicate를 파라미터로 받는 filter 메서드 생성

public static <V> List<V> filter(List<V> list, Predicate<V> p) {
    List<V> result = new ArrayList<>();
    for(V s : list) {
        if(p.test(s)) {
            result.add(s);
        }
     }
    return result;
}

파라미터로 던질 예시 list 

List<String> arrayStrings = Arrays.asList("choi", "", "jun", "", "woo");

실행

List<String> nonEmpty = filter(arrayStrings, ((String s)->!s.isEmpty()));
더보기

리펙토링

Predicate<String> nonEmptyStringPredicate = (String s) -> !s.isEmpty();
List<String> nonEmpty = filter(arrayStrings, nonEmptyStringPredicate);

2. Consumer 

제네릭 형식의 객체를 받아와서 void를 반환하는 추상 메서드를 정의 (accept)

list의 size 만큼 전략을 실행하는 메서드 생성

public static <T> void forEach(List<T> list, Consumer<T> c) {
    for(T t : list)
        c.accept(t);
}

Consumer로 리스트의 내용을 출력하는 전략을 전송

List<Integer> arrayIntegers = Arrays.asList(1, 2, 3, 4, 5);
forEach(arrayIntegers, (Integer i) -> System.out.println(i));

출력결과


3. Function

T로 받아서 R로 리턴

List를 받아서 결과 리스트에 저장하는 메서드 작성

public  static <T,R> List<R> map(List<T> list, Function<T,R> f) {

    List<R> result = new ArrayList<>();
    for(T t : list) {
        result.add(f.apply(t));
    }

    return result;
}

Function에 리스트의 길이를 반환하는 전략 전송

List<String> stringList = Arrays.asList("choi", "jun", "woo");
List<Integer> map = map(stringList, (String s) -> s.length());

기본형에 특화

: 예를 들어 제네릭을 받을 땐 참조형(Object, List, Integer, Byte) 밖에 구조상 받을 수 없다.

  • 따라서 오토 박싱을 하게 되는데 이는 너무 많은 비용이 든다.

오토 박싱을 하지 않고 캐스팅을 하는 함수형 인터페이스가 자바 8에는 존재한다.


람다, 함수형 인터페이스의 예외 사용 밥법 두 가지

 

1. 인터페이스에 예외를 직접 정의

 

2. 람다에 try catch로 예외를 정의


형식검사, 형식 추론, 제약

람다는 어떤 함수형 인터페이스의 메서드를 구현하는지 알 방법이 없다.

 

1. 형식검사 : 람다가 사용하는 context를 이용해서 람다의 형식을 알 수 있다.

2. 같은 람다 다른 함수형 인터페이스

: 같은 람다라도 다른 함수형 인터페이스의 추상 메서드를 사용할 수 있다.

  • 특별한 void 호환 규칙 : 람다의 바디에 일반 표현식이 존재하면 함수형 인터페이스의 리턴 값이 달라도 가능!(return void 만 가능)

3. 형식 추론

단순히 말하자면 람다식에 타입을 제외하고 변수만 선언할 수 있다는 말.

  1. 지역변수 사용 가능 :

전달받은 파라미터뿐만 아니라 지역변수도 사용 가능 하지만 지역변수는 final(상수)의 역할을 가진 변수만이 적용 가능하다.

  • 이유는 인스턴스 변수는 힙에 저장되어 객체가 소멸하는 순간까지 이어지지만 지역변수는 스택에 저장되어 변수의 사용이 달라지거나 끝나면 해당 변수를 람다가 참조할 수없기 때문이다.

메서드 레퍼런스

메서드 레퍼런스를 사용하는 이유는?

만약 람다가 메서드 호출을 명령한다면 어떤 메서드를 호출할 것인지에 대한 설명보단!

메서드명을 직접 참조하는 것이 가독성에 좋기 때문이다.

활용법 : " :: "

(Apple a) -> a.getWeight() Apple :: getWeight

메서드 레퍼런스를 만드는 방법 세 가지

  1. 정적 메서드 레퍼런스

Ex) Integer의 parseInt 메서드의 표현 : Integer :: parseInt

  1. 다양한 형식의 인스턴스 메서드 레퍼런스

Ex) String :: length

  1. 기존 객체의 인스턴스 메서드 레퍼런스
  • 외부 객체의 메서드를 호출 시

( ) -> expensiveTransaction.getValue() //expensiveTransaction : Transaction 객체를 할당받은 참조 변수 expensiveTransaction :: getValue


특별한 형식의 메서드 레퍼런스

ex) 대소문자 구분 없이 리스트를 정렬하는 코드

람다 표현식을 레퍼런스로 바꾸는 세 가지 방식


Code Link

https://github.com/mike6321/PURE_JAVA/tree/master/Java8/2Week/lamda

 

mike6321/PURE_JAVA

Contribute to mike6321/PURE_JAVA development by creating an account on GitHub.

github.com

References

자바 8 인 액션
국내도서
저자 : 라울-게이브리얼 우르마(RAOUL-GABRIEL URMA),마리오 푸스코(MARIO FUSCO),앨런 마이크로프트(ALAN MYCROFT) / 우정은역
출판 : 한빛미디어 2015.04.01
상세보기

'Java > Java8' 카테고리의 다른 글

(JAVA8) 함수형 인터페이스와 람다 표현식 (1)  (0) 2020.07.07
(JAVA8) 스트림의 활용 (2)  (0) 2020.01.19
(JAVA8) 람다식으로 향하는 과정  (0) 2020.01.16
(JAVA8) 스트림의 개요 (1)  (0) 2020.01.03
(JAVA8) 람다식 (1)  (0) 2020.01.03