함수형 인터페이스

김아무개·2023년 5월 11일

Java

목록 보기
13/23

Functional Interface

java 8에서 도입된 개념으로
정확히 하나의 추상 메서드를 가진 인터페이스를 말한다.

이 함수형 인터페이스는 람다 표현식으로 잘 활용된다.


자바에는 여러가지 내장된 함수형 인터페이스가 있지만,

특히 자바 공부할 때

기능 설명 부분에서 자주 볼 수 있었던

몇 가지 인터페이스에 대해서 정리 ✏️



Function<T, R>

매개변수     : T
Return 타입 : R
추상 메서드 : apply()
         기능 : T 타입의 인자를 받으며, R 타입의 결과를 반환한다.

사용 예시

기본 표현 방식 사용

public static void getLastIndex(String text) {

    Function<String, Integer> getBasicLastIndex = new Function<String, Integer>() {
        @Override
        public Integer apply(String s) {
            return s.length() - 1;
        }
    };

    System.out.println(
            getBasicLastIndex.apply(text)
    );
}

람다 표현 방식 사용

public static void getLastIndex(String text) {

    Function<String, Integer> getLambdaLastIndex = s -> s.length() - 1;

    System.out.println(
            getLambdaLastIndex.apply(text)
    );
}

Function 에서 사용할 수 있는 Default 메서드

🤓✏️ Default 메서드

자바 8에서 추가된 기능으로 

인터페이스에서 선언과 구현을 동시에 하는 방법이다.

인터페이스를 정의할 때 default 키워드를 사용하여 메서드를 작성하면 된다.

디폴트 메서드를 사용하면,

인터페이스에 새로운 메서드(default)를 추가하더라도 
기존에 사용중이던 클래스를 수정하지 않고도 인터페이스에 추가된 메서드를 사용할 수 있다.

주의 할 부분은
여러 인터페이스에서 동일한 디폴트 메서드를 제공하는 경우 
충돌이 발생할 수 있으므로 유의해서 사용해야 한다.

* andThen()

주어진 함수를 첫 번째 함수의 결과에 적용하여 새로운 자료형의 반환값을 반환한다.

f.andThen(g) 형태로 사용하며,
수학적으로 표현하면 g(f(x))와 같다.

Function<Integer, Integer> f1 = num -> num * 2;
Function<Integer, Integer> f2 = num -> num * num;

Function<Integer, Integer> f = f1.andThen(f2);
System.out.println(f.apply(3));

위에 작성한 코드를 보면
마지막 sout 문장 안에 있는 andThen 결과인 f에 3을 주었다.

3
f1에서 f1의 구현 내용으로 가공된 후 ,
반환값이f2에 들어가서 f2의 구현 내용에 따라 2차 가공되어 최종 반환된다.

이 경우
3 -> 3*2 -> 6*6 -> 36 순서로 값의 변화가 일어난다.

* compose()

compose()는 반대로 첫 번째 함수의 결과를 두 번째 함수에 적용한다.

f.andThen(g) 형태로 사용하며,
수학적으로 표현하면 f(g(x))와 같다.



아래 부터 소개하는 인터페이스의 디폴트 메서드는 나중에 정리 😵‍💫

Predicate<T>

매개변수     : T
Return 타입 : boolean
추상 메서드 : test()
         기능 : T 타입의 인자를 받으며 boolean을 반환한다.

사용 예시

기본 표현 방식 사용

public static void isEvenOdd() {

    Predicate<Integer> predicate = new Predicate<Integer>() {
        @Override
        public boolean test(Integer integer) {
            return integer % 2 == 0;
        }
    };
    
    System.out.println(
            predicate.test(2)
                    ? "짝수 입니다."
                    : "홀수 입니다."
    ); 
}

람다 표현 방식 사용

public static void isEvenOdd() {
    
    Predicate<Integer> predicate2 = i -> i % 2 == 0;

    System.out.println(
            predicate2.test(3)
                    ? "짝수 입니다."
                    : "홀수 입니다."
    );
}



Consumer<T>

매개변수     : T
Return 타입 : void
추상 메서드 : accept()
         기능 : T 타입의 인자를 받으며, 아무런 결과도 반환하지 않는다.

결과를 반환하지 않고 값을 사용하기만 해서 소비자인가 🙊

사용 예시

기본 표현 방식 사용

public static void print() {

    Consumer<String> consumer = new Consumer<String>() {
        @Override
        public void accept(String s) {
            System.out.printf("\"%s\" 입력 받았슴다 🤓\n", s);
        }
    };
    consumer.accept("가나다라");

}

람다 표현 방식 사용

public static void print() {

    Consumer<String> consumer2 = s -> System.out.printf("\"%s\" 입력 받았슴다 🤓\n", s);
    consumer2.accept("아자차카타파하하하하하");
    
}

메서드 참조 표현식 사용

메서드 참조 🤓✏️
> 지금은 간단히 적어두고 나중에 추가 공부 계획

자바 8에서 도입

이미 정의된 메서드를 람다 표현식 대신에 직접 참조할 수 있게 해준다.

4가지 유형의 사용 방법이 있음!

  1. 정적(static) 메서드 참조 : 클래스::정적메서드
    ex : Integer::parseInt

  2. 인스턴스 메서드 참조 : 인스턴스::메서드
    ex : System.out::println

  3. 비한정적 인스턴스 메서드 참조 : 클래스::메서드
    ex : String::length

  4. 생성자 참조 : 클래스::new
    ex : ArrayList::new

public static void print() {

    Consumer<String> consumer3 = System.out::println;
    consumer3.accept("하하 🙈");

}

이렇게 사용하면
Consumer.accept(T t) = System.out.println(t)
이런식으로 적용 된다.



Supplier<T>

매개변수     : void
Return 타입 : T
추상 메서드 : get()
         기능 : 인자를 받지 않고, T 타입의 결과를 반환한다.

오, Getter()랑 같은 기능!
그러면 반대로 동작하는 Consumer.accept() 는 Setter() !! 🙊

공급자는 get() == getter()
소비자는 accept() == setter()
🙊

주로 특정 값을 생성하거나,
계산하는데 사용된다고 한다.

사용 예시

기본 표현 방식 사용

public static void getNowTime() {

    Supplier<LocalDateTime> supplier = new Supplier<LocalDateTime>() {
        @Override
        public LocalDateTime get() {
            return LocalDateTime.now();
        }
    };
    System.out.println(
            supplier.get()
    );

}

람다 표현식 사용

public static void getNowTime() {
    
    Supplier<LocalDateTime> supplier2 = () -> LocalDateTime.now();
    System.out.println(
            supplier2.get()
    );

}

메서드 참조 방식 사용

public static void getNowTime() {
    
    Supplier<LocalDateTime> supplier3 = LocalDateTime::now;
    System.out.println(
            supplier3.get()
    );
    
}



UnaryOperator<T>

매개변수     : T
Return 타입 : T
추상 메서드 : T apply(T t)
         기능 : 인자로 T를 받고, T를 반환한다.

Function<T, T> 를 확장한 인터페이스 이다.
Function의 apply() 메서드를 그대로 사용한다.
Function과 UnaryOperator의 차이점으로는
Function은 매개변수와 결과값의 자료형이 달라질 수 있고
UnaryOperator는 매개변수와 결과값의 자료형이 같아야 한다.

사용 예시

기본 표현 방식 사용

public static void getPow() {

    UnaryOperator<Integer> uo = new UnaryOperator<Integer>() {
        @Override
        public Integer apply(Integer num) {
            return num * num;
        }
    };
    System.out.println( uo.get() );

}

람다 표현 방식 사용

public static void getPow() {

    UnaryOperator<Integer> uo = num -> num * num;
    System.out.println( uo.get() );

}



BinaryOperator<T>

매개변수     : T
Return 타입 : T
추상 메서드 : T apply(T t, T t)
         기능 : T 타입의 인자를 2개 받고, T를 반환한다.

사용 예시

기본 표현 방식 사용

public static void print(String str1, String str2) {

	BinaryOperator<String> bo = new BinaryOperator<String>() {
	    @Override
	    public String apply(String s, String s2) {
	        return s.length() >= s2.length() ? s : s2;
	    }
	};
	System.out.println( bo.apply("monkey", "monday..") );
    
}

람다 표현 방식 사용

public static void print2(String str1, String str2) {

	BinaryOperator<String> bo = (s, s2) -> s.length() >= s2.length() ? s : s2;
	System.out.println( bo.apply("monkey", "monday..") );

}





앞으로 강의 실습 계속 하면서 새롭고 낯선 함수형 인터페이스를 만나게 되면 추가할 계획!

profile
Hello velog! 

0개의 댓글