Supplier는 직역하면 제공자라는 뜻으로 타 함수와 다르게 매개변수를 받지 않고 특정 값을 반환하는 get이라는 추상메서드가 존재한다.
사용 예시는 간단하다.
public class Main {
public static void main(String[] args){
Supplier<String> helloWorldSupplier = () -> "hello world";
String result = helloWorldSupplier.get();
System.out.println(result);
}
}
위 처럼 Supplier로 구현하면 get() 추상메소드를 통해 return 값을 받아올 수 있다.
단순히 보면 그냥 "hello world"를 반환하는 함수를 만들거나 변수에 바로 넣으면 되는데 왜 귀찮게 Supplier를 사용하는 것일까??
3초 후, random 값을 반환하는 함수를 구현했다고 하자, 입력된 카운트 수 만큼 random 값을 출력하되 짝수 count 일 때만 출력한다면 총 얼만큼의 시간이 걸릴까?
카운트를 5만큼 주면 0, 2, 4 일때만 출력되기 때문에 약 9 + @ 만큼의 시간이 걸릴 것이라고 추측할 수 있다.
그러나 실제 코드를 돌려보면 다르다.
public class NoSupplier {
public static void main(String[] args) throws InterruptedException {
long startTime = System.currentTimeMillis();
for(int i = 0; i < 5; i++){
printRandom(getRandom(), i);
}
System.out.println((System.currentTimeMillis() - startTime)/1000 + "seconds");
}
public static double getRandom() throws InterruptedException {
TimeUnit.SECONDS.sleep(3);
return Math.random();
}
public static void printRandom(double d, int c){
if(c % 2 == 0){
System.out.println(d);
}
}
}
위처럼 구현 시, 함수가 실행되고 반환되는 결과값이 파라미터로 매핑된다. 즉 0,2,4 인 경우에만 random 값이 필요한데 실제로는 모든 count 값에 전부 실행이되서 성능이 악화된다.
반면 Supplier를 사용하면 상황이 바뀐다.
public class WithSupplier {
public static void main(String[] args){
long startTime = System.currentTimeMillis();
for(int i = 0; i < 5; i++){
printRandom(getRandom(), i);
}
System.out.println((System.currentTimeMillis() - startTime)/1000 + "seconds");
}
public static Supplier<Double> getRandom() {
return () -> {
try {
TimeUnit.SECONDS.sleep(3);
} catch (InterruptedException e) {
e.printStackTrace();
}
return Math.random();
};
}
public static void printRandom(Supplier<Double> d, int c){
if(c % 2 == 0){
System.out.println(d.get());
}
}
}
기존 Supplier를 사용하기 전에 15초 걸리던 로직이 사용하면 우리가 예측한대로 9초만에 계산된 것을 확인할 수 있다.
이처럼 함수 실행을 원하는 시점에 할 수 있도록 조절하는 것을 Lazy Evaluation이라고 하며 적절하게 사용할 시 높은 성능 향상을 가져올 수 있다.