Java Lambda & 함수형 인터페이스

엉엉 자바는 어려워·2022년 8월 3일
0

Lambda Expression

  • 익명객체로 하나로 함수를 하나의 식으로 표현한 것이다.

문법

(매개변수목록) -> {함수 바디}

Calculator c = (int num1, int num2) -> {return num1 + num2};
  1. 매개변수의 타입이 추론될 때는 타입을 생략할 수 있다.
Calculator cal = (num1, num2) -> {return num1 + num2;};
  1. 매개변수가 하나인 경우에는 괄호를 생략할 수 있다.
Calculator cal = num1 -> System.out.println(num1);
  1. 함수 바디가 하나의 명령문이면 중괄호를 생략할 수 있다.(;생략)
Calculator cal = (num1, num2) -> num1 + num2
  1. 함수 바디가 하나의 return 문으로 이루어진 경우엔 중괄호를 생략할 수 없다.
  • 1번 예제와 동일

장점

  1. 코드를 간결하게 만들 수 있다.
  2. 가독성이 높아진다.
  3. 함수를 만드는 과정 없이 한 번에 처리할 수 있어 생산성이 높아진다.
  4. 멀티스레드

단점

  1. 재사용이 불가능하다
  2. 디버깅이 어렵다.
  3. 재귀로 만들 경우에 부적합하다.

람다식 사용 조건

  • 인터페이스의 추상 메소드가 1개여야만 한다.
  • @FunctionalInterface 어노테이션을 사용하면 컴파일 에러를 알아서 잡아준다.

함수형 인터페이스란?

  • 1개의 추상 메소드를 갖고 있는 인터페이스를 말한다.

사용목적

  • 람다식으로 만든 객체에 접근하기 위해서이다.

Code

public interface FunctionalInterface {
     public abstract void doSomething(String text);
}

FunctionalInterface func = text -> System.out.println(tesxt);
func.doSomething("do something");
// 실행 결과
// do something

기본 함수형 인터페이스

  • Runnable
  • Supplier
  • Consumer
  • Function<T,R>
  • Predicate

Runnable

  • 인자를 받지 않고 리턴값도 없는 인터페이스이다.
Runnable runnable = () -> System.out.println("run anything!");
runnable.run();
// run anything!

Supplier

  • 인자를 받지 않고 T 타입의 객체를 리턴한다.
Supplier<String> str = () -> "Happy new year!";
System.out.println(str.get());
// Happy new year!

Consumer

  • T 타입의 객체를 인자로 받고 리턴 값은 없다.
  • andThen()을 사용하면 두 개 이상의 Consumer를 연속으로 실행할 수 있다.
public interface Consumer<T> {
    void accept(T t);

    default Consumer<T> andThen(Consumer<? super T> after) {
        Objects.requireNonNull(after);
        return (T t) -> { accept(t); after.accept(t); };
    }
}

Consumer<String> printString = text -> System.out.println("Miss " + text + "?");
printString.accept("me");
// Miss me?

Function

  • T타입의 인자를 받고, R타입의 객체를 리턴한다.
  • compose()는 두 개의 Function을 조합하여 새로운 Function 객체를 만들어준다. 인자로 전달되는 Function이 먼저 수행되고 그 후에 호출하는 객체의 Function 수행
public interface Function<T, R> {
    R apply(T t);

    default <V> Function<V, R> compose(Function<? super V, ? extends T> before) {
        Objects.requireNonNull(before);
        return (V v) -> apply(before.apply(v));
    }

    default <V> Function<T, V> andThen(Function<? super R, ? extends V> after) {
        Objects.requireNonNull(after);
        return (T t) -> after.apply(apply(t));
    }

    static <T> Function<T, T> identity() {
        return t -> t;
    }
}

Function<Integer, Integer> multiply = (value) -> value * 2;
Integer result = multiply.apply(3);
System.out.println(result);
// 6

Predicate

  • T타입 인자를 받고 결과로 boolean을 리턴한다.
  • and()와 or()은 다른 Predicate와 함께 사용된다.
  • isEqual()은 인자로 전달되는 객체와 같은지 체크하는 Predicate 객체를 만들어준다.
public interface Predicate<T> {
    boolean test(T t);

    default Predicate<T> and(Predicate<? super T> other) {
        Objects.requireNonNull(other);
        return (t) -> test(t) && other.test(t);
    }

    default Predicate<T> negate() {
        return (t) -> !test(t);
    }

    default Predicate<T> or(Predicate<? super T> other) {
        Objects.requireNonNull(other);
        return (t) -> test(t) || other.test(t);
    }

    static <T> Predicate<T> isEqual(Object targetRef) {
        return (null == targetRef)
                ? Objects::isNull
                : object -> targetRef.equals(object);
    }
}

Predicate<Integer> isBiggerThanFive = num -> num > 5;
System.out.println("10 is bigger than 5? -> " + isBiggerThanFive.test(10));
// 10 is bigger than 5? -> true

0개의 댓글