본문 바로가기
java

함수형 인터페이스와 람다

by 포잉띠 2024. 9. 5.

우선 메소드와 함수의 차이점부터 정리하겠다.

 

함수 : 독립되어 기능을 하는 코드뭉치

메소드 : 클래스, 인터페이스, Enum 등에 의존해야 하는 코드뭉치, 다른 말로 클래스 함수라고도 부른다.

 

왜 함수와 메소드를 집고 넘어가는가 하면 자바는 함수가 존재하지 않기에 

함수와 같은 기능을 구현하고자 도입된것이 함수형 인터페이스와 람다라고 생각하기 때문이다.

 

가볍게 함수형 인터페이스와 람다를 정리해 보겠다.

함수형 인터페이스

오직 단 하나의 추상 메소드만을 가지는 인터페이스.

 

람다

함수형 인터페이스의 추상 메소드를 구현하는 표현식

 


자바는 다른 언어처럼 함수가 독립적으로 존재할수가 없다. 그래서 익명함수, 람다표현식을 사용하더라도 상위에 함수형 인터페이스가 존재해야 하고, 함수형 인터페이스가 가진 메소드를 구현하는 방식으로 사용해야 한다.

 

왜 굳이 함수형 인터페이스가 존재해야만 람다를 쓸수 있을까 하는 의문이 정말 많이 들었지만

자바 컴파일러 특성 이슈때문에 어쩔수 없이 존재해야만 하더라. 정리해 보자면

  1.  자바 컴파일러는 람다 표현식이 어떤 메소드를 구현하는지 알아야 한다.
    함수형 인터페이스가 이 메소드를 정의함으로써, 람다 표현식을 어떤 함수로 해석할지 결정할 수 있다.
  2. 함수형 인터페이스가 여러개의 추상 메소드를 가질 수 없는 이유는 자바 컴파일러가 1번과 같이 정의해 주어야 해석할지 결정하는 녀석인데 그 안에 여러개가 있다면 람다 표현식이 어떤 메소드를 구현하는 것인지 헷갈려한다.
    이로 인해 함수형 인터페이스는 단 하나의 추상 메소드만 가져야 한다.
  3. 그나마 타입에는 조금 유연하다.
    자바 컴파일러가 람다 표현식의 매개변수 타입을 함수형 인터페이스의 시그니처(매개변수) 타입을 기반으로 추론하기 때문에 람다 표현식에 타입을 명시해도, 안해도 된다.

이렇게까지 정리를 하고난 뒤에 든 가장 큰 의문은

아니 그럼 매번 람다를 쓸때마다 함수형 인터페이스를 새롭게 하나씩 만들어야 하는건가?

였다.

 

다행히 아니었고 오라클 형님께서 자주 사용되는 함수형 인터페이스들을 미리 표준 함수형 인터페이스로 만들어서 제공해주신다고 한다.

java.util.function 패키지에 포함되어 있다.

 

가볍게 자주 사용되는 함수형 인터페이스 몇개를 정리해 보겠다.

 

Function<T, R>

하나의 입력(T)을 받아서 하나의 결과(R)를 반환하는 함수

// String 입력을 받으면 Integer타입의 결과를 반환한다.
// 아래코드의 내부 로직은 String의 length를 반환한다.
Function<String, Integer> lengthFunction = str -> str.length();
System.out.println(lengthFunction.apply("Hello"));  // 출력: 5

 

Consumer<T>

하나의 입력<T>을 받아서 아무 결과도 반환하지 않는 작업

return 타입이 void인 메소드를 생각하면 이해가 쏙쏙된다.

Consumer<String> printConsumer = str -> System.out.println(str);
printConsumer.accept("Hello, World!");  // 출력: Hello, World!

 

Supplier<T>

아무 입력도 받지 않고 값을 반환하는 함수

Supplier<Long> timeSupplier = () -> System.currentTimeMillis();
System.out.println(timeSupplier.get());  // 출력: 현재 시간(밀리초)

Consumer와 비슷하게 return타입이 void인 메소드이지만 매개변수가 없는 메소드, 

뭔가 다른 클래스 혹은 메소드를 호출하기 위한 메소드의 느낌이다.

 

Predicate<T>

하나의 입력(T)을 받아서 true / false 반환하는 함수

Predicate<String> isEmptyPredicate = str -> str.isEmpty();
System.out.println(isEmptyPredicate.test(""));  // 출력: true

 

BiFuncion<T, U, R>

두개의 입력(T, U)을 받아서 하나의 결과(R)를 반환하는 함수

BiFunction<Integer, Integer, Integer> addFunction = (a, b) -> a + b;
System.out.println(addFunction.apply(2, 3));  // 출력: 5

 

이것 외에도 

https://docs.oracle.com/en/java/javase/22/docs/api/java.base/java/util/function/package-summary.html

 

java.util.function (Java SE 22 & JDK 22)

JavaScript is disabled on your browser. Interfaces Represents an operation that accepts two input arguments and returns no result. Represents a function that accepts two arguments and produces a result. Represents an operation upon two operands of the same

docs.oracle.com

공식 API의 function을 보면 족히 30개는 넘어보인다.

람다는 사용방법, 사용처가 무궁무진한게 장점이지만 뭔가 이렇게 틀이 튼튼하게 잡혀있으니까 오히려 더 활용하기 어려운 느낌이 든다.

조금 더 알아봐야 할 것 같다.

'java' 카테고리의 다른 글

snmp4j 컨닝페이퍼  (0) 2024.09.10
Runnable과 Thread의 차이점  (0) 2024.09.05
TimeOut을 사용하는 대표적인 상황 몇가지  (0) 2024.08.27
JAVA Stream API 정리  (0) 2024.08.22
서블릿의 메소드와 핸들러,JUnit 개념 정리  (0) 2024.07.26