쵼쥬
쵼쥬의 개발공부 TIL
쵼쥬
전체 방문자
오늘
어제
  • 분류 전체보기 (276)
    • 코딩테스트 (192)
      • [알고리즘] 알고리즘 정리 (7)
      • [백준] 코딩테스트 연습 (126)
      • [프로그래머스] 코딩테스트 연습 (59)
    • Spring (71)
      • [인프런] 스프링 핵심 원리- 기본편 (9)
      • [인프런] 스프링 MVC 1 (6)
      • [인프런] 스프링 MVC 2 (4)
      • [인프런] 실전! 스프링 부트와 JPA 활용1 (7)
      • [인프런] 실전! 스프링 부트와 JPA 활용2 (5)
      • [인프런] 실전! 스프링 데이터 JPA (7)
      • [인프런] 실전! Querydsl (7)
      • JWT (5)
      • [인프런] Spring Cloud (17)
      • [인프런] Spring Batch (4)
    • Java (6)
      • [Java8] 모던인자바액션 (4)
      • [부스트코스] 웹 백엔드 (2)
      • [패스트캠퍼스] JAVA STREAM (0)
    • CS (6)
      • 디자인 패턴과 프로그래밍 패터다임 (2)
      • 네트워크 (4)

블로그 메뉴

  • 홈

공지사항

인기 글

태그

  • BFS
  • 알고리즘
  • jpa
  • 백준
  • 비트마스킹
  • 누적합
  • 타임리프
  • MVC
  • 위클리 챌린지
  • 스프링
  • 구현
  • 부스트코스
  • 백분
  • querydsl
  • 코딩테스트
  • 인프런
  • Spring Data JPA
  • 자바
  • spring
  • 프로그래머스

최근 댓글

최근 글

티스토리

hELLO · Designed By 정상우.
쵼쥬

쵼쥬의 개발공부 TIL

Java/[Java8] 모던인자바액션

람다 표현식

2022. 2. 11. 17:35

람다의 특징

익명 함수를 단순화 한것이라고 할 수 있다.

  • 익명
    • 이름이 없으므로 익명이라 표현한다. 구현해야할 코드에 대한 걱정거리가 줄어든다.
  • 함수
    • 람다는 메서드처럼 특정 클래스에 종속되지 않으므로 함수라고 부른다. 하지만 메서드처럼 파라미터 리스트, 바디, 반환 형식, 가능한 예외 리스트를 포함한다.
  • 전달
    • 람다 표현식을 메서드 인수로 전달하거나 변수로 저장할 수 있다.
  • 간결성
    • 익명 클래스처럼 많은 자질구레한 코드를 구현할 필요가 없다.
(String s) -> s.length();

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

(int x, int y) -> {
	System.out.println("Result:");
    System.out.println(x + y);
}

() -> 42

(Apple a1, Apple a2) -> a1.getWeight().compareTo(a2.getWeight());

 

함수형 인터페이스에서 람다 표현식을 사용할 수 있는데 함수형 인터페이스는 무엇인가???

 

함수형 인터페이스 : 오직 하나의 추상 메서드만 가지는 인터페이스 (많은 디폴트 메서드가 있어도 됨)

 

자바 API의 함수형 인터페이스 예시)

public interface Comparator<T>{
	int compare(T o1, T o2);
}

public interface Runnable{
	void run();
}

public interface ActionListener extends EventListener{
	void actionPerformed(ActionEvent e);
}

public interface Callalbe<T>{
	V call() throws Exception;
}

public interface PrivilegeAction<T>{
	T run();
}

 

함수 디스크립터

함수형 인터페이스의 추상메서드 시그너처는 람다표현식의 시그너처를 가리킨다.

람다 표현식의 시그너처를 서술하는 메서드를 함수 디스크립터라고 한다.

 

예) Runnable Interface의 유일한 추상메서드 run은 인수와 반환값이 없으므로 Runnable인터페이스는 인수와 반환값이 없는 시그너처.



 

Predicate

java.util.function.Predicate<T> 인터페이스는 test라는 추상 메서드를 정의하며 test는 제네릭 형식의 T의 객체를 인수로 받아 불리언을 반환한다. 앞에서 만들었던 인터페이스와 같은 형태인데 따로 정의할 필요없이 바로 사용할 수 있다.

@FunctionalInterface
public interface Predicate<T> {
    boolean test(T t);
}

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

List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
List<Integer> evenNumbers = filter(numbers, (Integer i) -> i % 2 == 0);

 

Consumer

java.util.function.Consumer<T> 인터페이스는 제네릭 형식 T 객체를 받아서 void를 반환하는 accept라는 추상 메서드를 정의한다.

@FunctionalInterface
public interface Consumer<T> {
    void accept(T t);
}

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

forEach(numbers, (Integer i) -> System.out.println(i));

 

Function

java.util.function.Function<T, R> 인터페이스는 제네릭 형식 T를 인수로 받아서 제네릭 형식 R 객체를 반환하는 추상 메서드 apply를 정의한다. 

예) String 리스트를 인수로 받아 각 String의 길이를 포함하는 Integer 리스트로 변환하는 map 메서르 정의

public interface Function<T, R> {
    R apply(T t);
}

public <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;
}

List<Integer> l = map(
        Arrays.asList("lamda", "in", "actino"),
        (String s) -> s.length()
);

 

Supplier

Supplier는 인자를 받지 않고 Type T 객체를 리턴하는 함수형 인터페이스입니다.

public class Main {
    public static void main(String args[]) {
        Supplier<String> supplier = () -> "hello";
        System.out.println(supplier.get());
    }
}

 

 

자바의 모든 형식은 참조형 (Byte, Integer, Object, List) 아니면 기본형 (int, double, byte, char)에 해당한다.

기본형 -> 참조형으로 변환하는 기능은 박싱

참조형 -> 기본형으로 변환하는 기능은 언박싱

 

자바는 프로그래머가 편리하게 코드를 구현할 수 있도록 오토박싱 기능을 제공한다. 하지만 박싱한 값은 메모리를 더 소비하며 기본형을 가져올 때도 메모리를 탐색하는 과정이 필요하다. 

그래서 오토박싱을 피할 수 있는 함수형 인터페이스를 제공한다.

예) 

  • Predicate<T> - IntPredicate, LongPredicate, DoublePredicate
  • Consumer<T> - IntConsumer, LongConsumer, DoubleConsumer

함수형 인터페이스는 확인된 예외를 던지는 동작을 허용하지 않는다. 즉, 예외를 던지는 람다식을 표현하려면 예외를 선언하는 함수형 인터페이스를 직접 정의하거나 람다를 try/catch 블록으로 감싸야 한다.

 

메서드 참조

  • 정적 메서드 참조
    • Integer의 parseInt 메서드는 Integer::parseInt로 표현할 수 있다.
  • 다양한 형식의 인스턴스 메서드 참조
    • String의 length 메서드는 String::length로 표현할 수 있다.
    • 예) (String s) -> s.toUpperCase() 변환 => String::toUpperCase
  • 기존 객체의 인스턴스 메서드 참조
    • Transaction 객체를 할당받은 expensiveTransaction 지역 변수가 있고, Transaction 객체에는 getValue 메서드가 있다면, 이를 expensiveTranscation::getValue라고 표현할 수 있다.
    • 예) () -> expensiveTransaction.getValue() 변환 => expensiveTransaction::getValue()

 

ToIntFunction<String> stringToInt1 = (String s) -> Integer.parseInt(s);
ToIntFunction<String> stringToInt2 = Integer::parseInt;

BiPredicate<List<String>, String> contains1 = (list, elements) -> list.contains(elements);
BiPredicate<List<String>, String> contains2 = List::contains;

Predicate<String> startsWithNumber1 = (String string) -> this.startsWithNumber(string);
Predicate<String> startsWithNumber2 = this::startsWithNumber;

 

 

생성자 참조

Supplier<Apple> c1 = Apple::new;    // 메서드(생성자) 참조형
Apple a1 = c1.get();

Supplier<Apple> c1 = () -> new Apple();     // 람다 표현식
Apple a1 = c1.get();

// Integer weight를 갖는 생성자 Apple(Integer weigth)
Function<Integer, Apple> c2 = (weight) -> new Apple(weight);
Apple a2 = c2.apply(110);

Function<Integer, Apple> c2 = Apple::new;
Apple a2 = c2.apply(110);

 

람다, 메서드 참조 활용

    /** 코드 전달 */
class AppleComparator implements Comparator<Apple> {
	
    @Override
    public int compare(Apple o1, Apple o2) {
        return o1.getWeight().compareTo(o2.getWeight());
    }
}
	inventory.sort(new AppleComparator());
	
    
    /** 익명클래스 */
    inventory.sort(new Comparator<Apple> {
        @Override
        public int compare (Apple o1, Apple o2){
            return o1.getWeight().compareTo(o2.getWeight());
        }
    });
    
    
    /** 람다 표현식 */
    inventory.sort((Apple o1, Apple o2) ->
        o1.getWeight().compareTo(o2.getWeight())
    );
    
    inventory.sort((o1, o2) -> o1.getWeight().compareTo(o2.getWeight()));
	
    // Comparator는 Comparable 키를 추출해서 Comparator 객체로 만드는 Function 함수를 인수로 받는 정적 메서드 comparing을 포함한다.
	Comparator<Apple> c = Comparator.comparing((Apple o) -> o.getWeight());
	
    import static java.util.Comparator.comparing;
    inventory.sort(comparing(apple -> apple.getWeight()));
    
    
    /** 메서드 참조 */
    inventory.sort(comparing(Apple::getWeight));

 

람다 표현식을 조합할 수 있는 유용한 메서드

Comparator 조합

Comparator<Apple> c = Comparator.comparing((Apple o) -> o.getWeight());

 

역정렬

인터페이스 자체에서 주어진 reverse라는 디폴트 메서드 사용

inventory.sort(comparing(Apple::getWeight).reversed());	// 무게를 내림차순으로 정렬

 

Comparator 연결

thenComparing 메서드는 두번째 비교자를 만들 수 있다.

comparing 메서드의 첫번째 비교자를 이용해서 두 객체가 같다고 판단되면 두 번째 비교자에 객체를 전달한다.

inventory.sort(comparing(Apple::getWeight)
	.reversed()		// 무게를 내림차순으로 정렬
    	.thenComparing(Apple::getCountry));	// 두 사과 무게가 같으면 국가별로 정렬

 

 

Predicate 조합

Predicate 인터페이스는 복잡한 프레디케이트를 만들 수 있도록 negate, nad, or 세가지 메서드를 제공한다.

// 빨간색이 아닌 사과처럼 특정 프레디케이트를 반전시킬때 negate 
Predicate<Apple> notRedApple = redApple.negate();

// 빨간색이면서 무거운 사과 and
Predicate<Apple> redAndHeavyApple = redApple.and(apple -> apple.getWeight() > 150);

// 빨간색이면서 무거운 사과 또는 그냥 녹색 사과 or
Predicate<Apple> redAndHeavyAppleOrGreen 
	= redApple.and(apple -> apple.getWeight() > 150).or(apple -> GREEN.equals(a.getColor()));


Function 조합

Function 인터페이스는 andThen, compose 두가지 디폴트 메서드를 제공한다.

 

andThen : 주어진 함수를 적용한 결과를 다른 함수의 입력으로 전달하는 함수 반환

Function<Integer, Integer> f = x -> x + 1;
Function<Integer, Integer> g = x -> x * 2;
Function<Integer, Integer> h = f.andThen(g);	// 수학적으로 g(f(x))로 표현
int result = h.apply(1); 	// 4 반환

 

compose : 인수로 주어진 함수를 먼저 실행한 다음에 그 결과를 외부 함수의 인수로 제공

즉, andThen 대신 compose 사용하면 g(f(x))가 아니라 f(g(x))라는 수식이 된다.

 

 

'Java > [Java8] 모던인자바액션' 카테고리의 다른 글

스트림 활용  (0) 2022.02.15
스트림  (0) 2022.02.15
동작 파라미터화 코드 전달  (0) 2022.02.09
    'Java/[Java8] 모던인자바액션' 카테고리의 다른 글
    • 스트림 활용
    • 스트림
    • 동작 파라미터화 코드 전달
    쵼쥬
    쵼쥬

    티스토리툴바