자바8 부터는 람다 표현식
을 사용할 수 있게 되며 보다 직관적이면서 간단한 개발이 가능해졌습니다.
그리고 이를 아주 잘 활용하기 위한 수단으로 함수형 인터페이스
라는 것이 존재합니다.
@FunctionalInterface
interface hahaha() {
void method();
}
함수형 인터페이스란 기본적으로 메서드를 하나 가지고 있는 메서드를 지칭합니다.
그리고 이러한 함수형 인터페이스는 인터페이스 위에 @FunctionalInterface
를 쓰면 정의할 수 있죠.
해당 어노테이션을 사용하면, 인터페이스가 단 하나의 메서드만을 가지도록 강제할 수 있습니다.
자바에서 기본적으로 제공하는 여러 함수형 인터페이스가 존재합니다.
java.util.function
패키지 아래에 정의되어 있는 클래스들이죠(java 17 기준)
그럼 하나 하나 알아보도록 하겠습니다.
Consumer
는 특정 형태의 데이터를 받아서 아무것도 반환하지 않는 함수형 인터페이스 입니다.
람다식 표현은 T -> void
입니다
말 그대로 소비자처럼 데이터를 소비한다고(?) 생각하면 좋습니다.
Supplier
는 아무것도 받지 않고, 특정한 데이터를 리턴해줍니다.
람다식 표현은 void -> T
와 같습니다.
공급자라는 이름에 걸맞게, 데이터를 공급한다?고 생각하면 편합니다.
Predicate
는 특정 데이터를 받아서 true, false 둘 중 하나이 값을 리턴해주는 함수형 인터페이스 입니다.
람다식은 T -> boolean
와 같습니다.
이것 역시 이름에 걸맞게 무언가를 Y/N 로 예측한다?
로 생각하면 좋겠네요
Function
은 하나의 데이터 타입을 받아서 다른 데이터 타입으로 바꿔주는 함수형 인터페이스입니다.
람다식은 T -> R
입니다.
어쩌면 가장 많은 사람들이 알고있을(?)Runnable
입니다.
아무것도 받지 않고, 아무것도 뱉지 않는 함수형 인터페이죠
람다식은 void -> void
입니다.
Supplier
와 거의 동일한Callable
입니다.
이 녀석도 아무것도 받지 않은 다음 특정데이터 형을 리턴해주죠.
람다식은 void -> V
와 같습니다.
그렇다면 왜 함수형 인터페이스를 사용하는 것일까요?
그 이유는 람다식과 함께 조합하면 익명 클래스의 선언을 대체할 수 있기 때문입니다.
람다는 익명 함수로서 일급 객체처럼 다룰 수 있습니다.
이로 인해 이전보다 코드가 더 간결해지고, 가독성이 높아지게 되죠
그렇다면 이렇게 좋은 함수형 인터페이스를 좋은 사용 방법이 있지 않을까요?
아래와 같은 수칙을 지키면서 사용하면 함수형 인터페이스를 더 효율적으로 사용할 수 있습니다!
해당 활용 방법은 Baekdung
님의 블로그에서 발췌했습니다.
위에서 설명한 Consumer
, Predicate
등의 기본으로 제공하는 함수형 인터페이스로 웬만한 상황에서 충분히 사용 가능합니다.
두 개의 파라미터를 받기도 하는 BiConsumer
까지 존재하니 말은 다 햇죠.
웬만한 상황에서는 굳이 사용자가 직접 생성할 필요가 없습니다.
해당 어노테이션을 붙이면 다음과 같은 이점을 얻을 수 있습니다.
프로젝트가 커질 경우, 이런 표시를 해주지 않으면, 누군가가 메서드를 추가할 수 있습니다.
그렇기 때문에 해당 어노테이션으로 함수형 인터페이스 임을 표시해주는 것이 좋습니다.
코드는 짧을 수록 좋죠.
그리고 람다도 코드고요
람다는 표현식이지, 설명이 아닙니다. 그렇기 때문에 최대한 짧게 유지하는 것이 좋습니다.
final 키워드가 붙지 않은 변수를 람다 표현식 안에서 사용하려고 시도하면 컴파일 에러가 발생합니다.
하지만 모든 변수에 final 키워드를 붙여야 하는 것은 아니죠
실질적으로 final
이라는 개념에 의하면, 변수에 값이 딱 1번만 할당될 경우, final
과 같이 취급합니다.
이러한 변수들은 람다표현식안에서 사용해도 안전합니다.
대신 해당 변수의 값이 변경되면 컴파일러는 즉시, 컴파일 에러를 뱉겠죠
이외에도 다양한 팁들이 존재합니다.
제 생각에 개발의 꽃은 람다식을 활용해서 능숙하면서 가독성 좋은 코드를 작성하는 것입니다.
언젠가 저도 고수의 반열에 오를 수 있으면 좋겠네요