[Java] 함수형 인터페이스

Minjun Kang·2022년 12월 27일
0

basic-java

목록 보기
1/5

함수형 인터페이스

  • Single Abstract Method (SAM, 단일 추상 메소드)
  • default method 또는 static method가 있더라도, 실질적으로 구현해야하는 추상 메소드가 단 1개.

    JAVA8 이후로 인터페이스 내부의 default method 와 static method를 선언 가능하다.
    [단, 인터페이스는 class와 달리 위계구조가 없으므로 접근 제어자를 설정 불가능 (항상, public으로 취급)]

/* 함수형 인터페이스 예시 */

@FunctionalInterface // 컴파일 타임에 SAM인지 판단. 아닐 경우 Compile Error 
public interface SomeFunctionalInterface {
	public void doSomething();
    public default void sayHello() {
    	System.out.println("hello");
    }
    public static void sayBye() {
    	System.out.println("bye");
    }
}

함수형 인터페이스는 왜 사용할까?

  • 함수형 프로그래밍을 도와주는 인터페이스
  • Side effect 없이 Stateless한 입력값에 대하여 항상 동일한 출력값을 보장해준다. (순수 함수) -> 병렬 처리 용이
  • 함수형 인터페이스의 구현체를 객체 취급하므로서 누릴 수 있는 장점이 많다. (일급 객체)
  • 다른 함수형 인터페이스와 결합하여 새로운 함수형 인터페이스를 만들어 낼 수 있다. (고차 함수)
  • 구현체들의 동작이 일회적인 경우가 많을 경우, 람다식을 이용하여 간단하게 구현 가능하다.

    메소드를 수학적인 함수와 동일하게 취급하므로서, 누릴 수 있는 이점 때문에 사용한다.

프로그래밍의 패러다임이 변화하면서, 행위 그 자체도 런타임에 유연하게 변경되어야 할 필요성이 대두되었다.
행위 자체를 메소드로 표현하여, 그것을 다른 메소드로 전달할 수 있는 방법이 필요했다. 하지만, 자바의 메소드는 일급 객체가 아니였기 때문에 이러한 역할을 수행할 수 있는 다른 매개체가 필요했는데 이것이 함수형 인터페이스이다.

함수형 인터페이스 사용 예시 - 1) 외부 클래스 활용

// 해당 클래스를 외부에 정의하여, 생성자나 팩토리를 이용하여 생성하는 방법
public class OuterClass implements SomeFunctionalInterface {
	@Override
	public void doSomething() {
    	System.out.println("~~ㅇㅅㅇ~~");
    }
}

이 방법은 어느 인터페이스에서나 흔히 접할 수 있는 방법이다. 주로, 재사용성이 높을 경우 사용한다.

함수형 인터페이스 사용 예시 - 2) 익명 내부 클래스 활용

public class Main {
	public static void main(String[] args) {
    	// 익명 클래스 활용
    	SomeFunctionalInterface impl = new SomeFunctionalInterface {
        	@Override
        	public void doSomething() {
            	System.out.println("~~aㅅa~~");
            }
        }
    	
    }
}

실제로 위 방법은, 자바8 이전에 많이 쓰였던 방법이다. 주로 재사용성이 떨어지는 행위를 표현하기 위하여 많이 사용하였다.
자바8 이후로 더 나은 방법이 존재한다. 아래를 살펴보자

함수형 인터페이스 사용 예시 - 3) Lambda expression 활용

public class Main {
	public static void main(String[] args) {
    	// 람다 활용
    	SomeFunctionalInterface impl = () -> System.out.println("~~ㅁㅅㅁ~~");
    }
}

내부 익명 클래스와 비교해보면, 람다식이 더 직관적이고 간결하다는 것을 확인해볼 수 있다.
Java8 이후로는 이러한 람다식을 언어 자체에서 지원한다.
람다의 리턴 값은 함수형 인터페이스 이다. 특정한 행위를 인라인 형식으로 표현하는 람다식은 함수형 인터페이스와 완벽하게 호환된다.

함수형 인터페이스: 클래스 기반 구현 vs 람다식을 활용한 구현

내부 클래스든 외부 클래스든 클래스는 자신만의 고유한 Scope를 가진다.
그에 비해서, 람다식은 해당 람다식을 정의한 클래스의 Scope에서 정의되므로 고유한 Scope를 가지지 않는다.
이 때문에, 람다식 내부에서는 람다식을 선언한 외부 클래스에서 사용하는 변수와 동일한 이름을 가진 변수를 선언할 수 없다.

자바에서 제공하는 함수형 인터페이스

레퍼런스
흔히 많이 사용할 법한 함수형 인터페이스들은 자바에서 직접 제공해주고있다.
이 중, 몇몇은 특정 함수형 인터페이스의 확장판(?)이다. 가장 많이 쓰이는 함수형 인터페이스를 살펴보자.

  1. Predicate<T> : T타입의 인자를 받아서 boolean을 리턴하는 함수형 인터페이스
  • 조건식을 표현하기 위해 사용한다. (이름도 그렇다..!)

  1. Consumer<T> : T타입의 인자를 받아서 void를 리턴하는 함수형 인터페이스
  • 주로, 인자를 받아서 내부 처리를 하기 위해서 사용된다.
  • ex) 메세지 큐에서 메세지를 가져오는 행위를 수행하는 사용자는 Consumer의 역할을 한다

  1. Supplier<T> : 아무런 인자를 받지 않고 T타입의 인자를 리턴하는 함수형 인터페이스
  • 주로, '공급자'의 입장으로서 특정 값을 전달만 해주는 역할을 수행한다.
  • ex) 메세지 큐에서 메세지를 생성하는 행위를 수행하는 사용자는 Supplier의 역할을 한다.

  1. Function<T,R> : T타입의 단일 인자를 받아서 R타입의 인자를 반환하는 함수형 인터페이스
  • f(x)=yf(x) = y 를 표현하기에 적절해보인다.

etc) 그 외 Bi~~ , Unary~~ 라는 접두사를 사용하는 함수형 인터페이스는 기존 ~~라는 함수형 인터페이스에서 특수한 성질이 추가된 함수형 인터페이스이다.

  • Unary~~ : 입력 값과 리턴 값의 인자 타입이 같다.
  • Bi~~: 입력 값이 단일 인자가 아닌 2개의 인자로 구성되어있다.
profile
성장하는 개발자

0개의 댓글