Supplier Interface 는 함수형 프로그래밍을 지원하는 인터페이스 중 하나이다.
Supplier 는 매개변수를 받지 않고 값을 반환하는 함수를 나타내며, 일반적으로 람다 표현식을 사용하여 함수형 인터페이스의 구현체로 활용된다.
Supplier 인터페이스는 다음과 같이 하나의 추상 메서드인 get() 을 가지고 있다.
package java.util.function;
/**
* Represents a supplier of results.
*
* <p>There is no requirement that a new or distinct result be returned each
* time the supplier is invoked.
*
* <p>This is a <a href="package-summary.html">functional interface</a>
* whose functional method is {@link #get()}.
*
* @param <T> the type of results supplied by this supplier
*
* @since 1.8
*/
@FunctionalInterface
public interface Supplier<T> {
/**
* Gets a result.
*
* @return a result
*/
T get();
}
이 메소드는 매개변수를 받지 않고 제네릭 타입의 T 객체를 반환한다. 즉, get() 메소드를 제공하면 T 타입의 값을 제공하는 로직이 실행되어야 한다.
간단한 사용법 예시를 들어보겠다.
class Main {
public static void main(String[] args) {
// Supplier를 사용하여 랜덤한 정수를 생성하는 구현체를 정의
Supplier<Integer> randomSupplier = () -> {
Random random = new Random();
return random.nextInt(100); // 0부터 99까지의 랜덤한 정수를 반환.
};
// Supplier를 호출.
int randomNumber = randomSupplier.get();
System.out.println("Random number: " + randomNumber);
}
}
Supplier Interface 는 주로 값을 생성하는 로직을 캡슐화하고 전달하는 데 사용된다.
예를 들어, 데이터베이스에서 데이터를 가져오거나, 외부 서비스에서 데이터를 요청하는 등의 작업을 수행할 때 사용된다.
또한, Supplier Interface 의 진정한 효용 가치는 Lazy Evaluation 효과를 얻을 수 있는 데에 있다.
Supplier 는 호출되기 전까지 값을 생성하지 않고, 실제로 값을 필요로 하는 시점에 생성하기 때문에 자원을 효율적으로 활용하고 성능을 향상시킬 수 있다.
특히 비용이 많이 드는 작업이나 큰 데이터를 다룰 때 유용하다.
예를 들어보자.
public class SupplierTest {
public static void main(String[] args) throws InterruptedException {
long startTime = System.currentTimeMillis();
for (int i = -1; i < 4; i++) {
printRandom(i, getRandom());
}
System.out.println((System.currentTimeMillis() - startTime) / 1000 + "seconds");
}
static double getRandom() throws InterruptedException {
TimeUnit.SECONDS.sleep(2);
return Math.random();
}
static void printRandom(int x, double d) {
if (x > 0) {
System.out.println(d);
}
}
}
위 코드는 매개변수 x 가 양수일 때 d 값을 출력하는 함수이다.
이 때 getRandom() 메소드는 조건에 상관없이 실행되기 때문에 전체 실행 시간이 10초가 걸리게 된다.
만약 getRandom() 메소드의 연산 처리 비용이 매우 비싸다고 가정한다면, 이것은 엄청난 자원의 손실로 이어질 것이다.
반면 같은 코드를 Supplier Interface 를 활용해 다음과 같이 리팩토링 할 수 있다.
public class SupplierTest {
public static void main(String[] args) throws InterruptedException {
long startTime = System.currentTimeMillis();
for (int i = -1; i < 4; i++) {
printRandom(i, getRandomWithSupplier());
}
System.out.println((System.currentTimeMillis() - startTime) / 1000 + "seconds");
}
static Supplier<Double> getRandomWithSupplier() {
return () -> {
try {
TimeUnit.SECONDS.sleep(2);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
return Math.random();
};
}
static void printRandom(int x, Supplier<Double> d) {
if (x > 0) {
System.out.println(d.get());
}
}
}
위 코드는 Supplier 를 사용하여 Lazy Evaluation 을 구현했기 때문에, 실제 필요한 시점에 getRandomWithSupplier() 메소드가 실행되게 된다.
따라서 결과값을 확인하면 전체 실행 시간이 6초가 걸리게 될 것이다.
'자바' 카테고리의 다른 글
[JAVA] @Retention 어노테이션 알아보기 (0) | 2024.03.25 |
---|---|
리플렉션(Reflection) (0) | 2023.07.11 |
[JVM] 실행 엔진 알아보기 - (3) / 인터프리터, JIT Compiler, GC (0) | 2023.05.17 |
[JVM] 런타임 영역 알아보기 -(2) (0) | 2023.05.16 |
[JVM] Class Loader 알아보기 - (1) (0) | 2023.05.16 |