[Java] Java8 표준 함수형 인터페이스

2023. 11. 1. 22:15·Language/Java

 

Java 8에서 기본으로 제공하는 함수형 인터페이스는 무엇이 있을까?

 

참고링크

 

1. 표준 함수형 인터페이스

  • Java 8부터 기본으로 제공하는 함수형 인터페이스
  • Java.lang.function 패키지

 

활용 예시

  • ArrayList 클래스의 forEach 메소드를 보면  Consumer<T>를 매개 값으로 활용하고 있는 것을 알 수 있다
  • Consumer<T> : T를 받아서 아무 값도 리턴하지 않는 함수형 인터페이스
public class ArrayList<E> extends AbstractList<E>

    @Override
    public void forEach(Consumer<? super E> action) {
        Objects.requireNonNull(action);
        final int expectedModCount = modCount;
        final Object[] es = elementData;
        final int size = this.size;
        for (int i = 0; modCount == expectedModCount && i < size; i++)
            action.accept(elementAt(es, i));
        if (modCount != expectedModCount)
            throw new ConcurrentModificationException();
    }
}

 

따라서 람다를 활용하여 편하게 ArrayList를 출력할 수 있다.
public class Exe {

    public static void main(String[] args) {
    
        ArrayList<String> names = new ArrayList<>();
        names.add("B");
        names.add("D");
        names.add("A");
        names.add("C");
        
        names.forEach(name -> System.out.println(name));    
    }
}

 

2. Function<T, R>

  • 구현할 추상 메소드 = R apply(T t);
  • T 타입을 받아서 R을 리턴
@FunctionalInterface
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;
    }
}

 

사용 예시 1

import java.util.function.Function;

public class Test {

    public static void main(String[] args) {
    
        // 익명 내부 클래스로 구현
        Function<Integer, String> numberToStringInner = new Function<Integer, String>() {
            @Override
            public String apply(Integer integer) {
                return integer.toString();
            }
        };

        // 람다를 활용하여 구현
        Function<Integer, String> numberToStringLambda = num -> Integer.toString(num);

        System.out.println(numberToStringInner.apply(10) + " : " + numberToStringInner.apply(10).getClass());
        System.out.println(numberToStringLambda.apply(10) + " : " + numberToStringLambda.apply(10).getClass());
    }
}
람다형식이 더 가독성이 좋다

 

사용 예시 2

  • andThen(), compose()를 활용하여 조합해서 사용할 수 있다.
  • andThen() = 현재 메소드를 실행 후 매개 변수로 받은 함수를 나중에 처리.
  • compose() = 매개 변수로 받은 함수를 먼저 처리. ( andThen()과 반대 )
import java.util.function.Function;

public class Test {

    public static void main(String[] args) {

        Function<Integer, Integer> plus10 = num -> num+10;
        Function<Integer, Integer> div2 = num -> num/2;

        System.out.println("plus10(10) : " + plus10.apply(10));
        System.out.println("div2(10) : " + div2.apply(10));
        System.out.println("plus10.andThen(div2).apply(10) : " + plus10.andThen(div2).apply(10)); // (10+10)/2
        System.out.println("plus10.compose(div2).apply(10) : " + plus10.compose(div2).apply(10)); // (10/2)+10
    }
}

 

 

3. BiFunction<T, U, R>

  • 구현할 추상 메서드 = R apply(T t, U u);
  • T, U를 받아서 R타입으로 반환하는 인터페이스
@FunctionalInterface
public interface BiFunction<T, U, R> {

    R apply(T t, U u);

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

 

사용 예시

import java.util.function.BiFunction;

public class Test {

    public static void main(String[] args) {

        BiFunction<Integer, Integer, String> addToString = (num1, num2) -> Integer.toString(num1 + num2);
        System.out.println(addToString.apply(1,2) + " : " + addToString.apply(1,2).getClass());
    }
}

 

 

4. UnaryOperator<T>

  • 입력값 하나를 받아서 동일한 타입을 리턴하는 함수 인터페이스
  • Function<T, R>의 특수한 형태로 Function<T, T>를 상속 받음, 따라서 apply()로 구현
@FunctionalInterface
public interface UnaryOperator<T> extends Function<T, T> {

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

 

사용 예시

import java.util.function.UnaryOperator;

public class Test {

    public static void main(String[] args) {

        UnaryOperator<Integer> plus50 = (i) -> i + 50;
        UnaryOperator<Integer> multiply2 = (i) -> i * 2;

        System.out.println(plus50.andThen(multiply2).apply(5));
    }
}

 

 

5. BinaryOperator<T>

  • 동일한 타입의 입력값 두 개를 받아 리턴하는 함수 인터페이스
  • BiFunction<T, U, R>의 특수한 형태로 BiFunction<T,T,T>를 상속받음. 따라서 apply()로 구현
@FunctionalInterface
public interface BinaryOperator<T> extends BiFunction<T,T,T> {

    public static <T> BinaryOperator<T> minBy(Comparator<? super T> comparator) {
        Objects.requireNonNull(comparator);
        return (a, b) -> comparator.compare(a, b) <= 0 ? a : b;
    }

    public static <T> BinaryOperator<T> maxBy(Comparator<? super T> comparator) {
        Objects.requireNonNull(comparator);
        return (a, b) -> comparator.compare(a, b) >= 0 ? a : b;
    }
}

 

사용 예시

import java.util.function.BinaryOperator;

public class Test {

    public static void main(String[] args) {

        BinaryOperator<String> introduce = (name, food) -> "My name is " + name + " I like " + food;
        System.out.println("introduce(veneas, chicken) : "+ introduce.apply("veneas", "chicken"));
    }
}

 

 

6. Consumer<T>

  • 구현할 추상 메소드 = void accept(T t);
  • T를 받아서 아무 값도(void) 리턴하지 않는다
@FunctionalInterface
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); };
    }
}

 

사용 예시

import java.util.Arrays;
import java.util.List;
import java.util.function.Consumer;

public class Test {

    public static void main(String[] args) {

        Consumer<String> printName = System.out::println;
        List<String> fruits = Arrays.asList("AAPL", "MSFT", "GOOGL");
        Consumer<List<String>> lowerCase = list -> list.forEach(e -> System.out.print(e.toLowerCase() + " "));

        printName.accept("veneas");
        lowerCase.accept(fruits);
    }
}

 

 

7. Supplier<T>

  • 구현할 추상 메서드 = T. get();
  • 아무 값도 받지 않고 T를 반환
@FunctionalInterface
public interface Supplier<T> {

    T get();
}

 

사용 예시

import java.util.function.Supplier;

public class Test {

    public static void main(String[] args) {

        Supplier<Integer> get10 = () -> 10;
        System.out.println("get10 : " + get10.get());
    }
}

 

8. Predicate<T>

  • 구현할 추상 메소드 = boolean test(T t);
  • T를 받아서 boolean(true, false)를 반환
@FunctionalInterface
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);
    }

    @SuppressWarnings("unchecked")
    static <T> Predicate<T> not(Predicate<? super T> target) {
        Objects.requireNonNull(target);
        return (Predicate<T>)target.negate();
    }
}

 

사용 예시

import java.util.function.Predicate;

public class Test {

    public static void main(String[] args) {

        Predicate<String> containJava = s -> s.contains("Java");
        Predicate<Integer> isEven = (i) -> i%2 == 0;
        Predicate<Integer> moreThan5 = (i) -> i>5;

        System.out.println("containJava(Java) : "+ containJava.test("Java")); // true
        System.out.println("containJava(Python) : " + containJava.test("Python")); // false
        System.out.println("isEven(10) : " + isEven.test(10)); // true
        System.out.println("moreThan5.and(isEven).test(6) : " + moreThan5.and(isEven).test(6)); // true
        System.out.println("moreThan5.or(isEven).test(4) : " + moreThan5.or(isEven).test(3)); // false
    }
}
저작자표시 (새창열림)
'Language/Java' 카테고리의 다른 글
  • [Java] Function 인터페이스를 활용한 조회 로직 개선
  • [Java] 오버로딩(OverLoading)??
  • [Java] ::new 는 무엇일까? Java 8 메소드 레퍼런스 (Method Reference)
  • [Java] Java8 Optional : orElse, orElseThrow, orElseGet
마볼링
마볼링
개발과 게임에 관한 내용을 읽기 쉽게 정리합니다.
  • 마볼링
    게임을 좋아하는 개발자의 블로그
    마볼링
  • 전체
    오늘
    어제
    • 분류 전체보기
      • Project
        • LOATODO
        • 인스타그램 클론코딩(중단)
      • Language
        • Java
        • PHP
        • Javascript
      • Framework & Library
        • Spring
        • Vue
      • Computer Science
        • Web
        • Linux
      • CodingTest
        • Algorithm
        • Kotlin으로 푼 코딩 테스트
        • Java로 푼 코딩 테스트
        • Sorting & Thinking
        • BFS
      • 책&강의 정리
      • 정보처리기사
      • 개인
        • 팰월드(PALWORLD)
        • 마인크래프트
  • 블로그 메뉴

    • 링크

      • GitHub
      • Threads
    • 공지사항

    • 인기 글

    • 태그

      운영체제
      오블완
      LoaTodo
      네트워크
      CS
      php
      error
      Database
      springboot
      로아투두
      Spring
      프로그래머스
      아크 서바이벌
      jsp
      JPA
      코딩테스트
      codingtest
      티스토리챌린지
      java
      이터널 모드
    • 최근 댓글

    • 최근 글

    • hELLO· Designed By정상우.v4.10.1
    마볼링
    [Java] Java8 표준 함수형 인터페이스
    상단으로

    티스토리툴바