IT/JAVA

Java 함수형 인터페이스 Supplier, Runnable

iamhyeon 2025. 12. 7. 13:21

 

Java 8 이후 큰 변화 중 하나가 함수형 인터페이스(Functional Interface) 기반의 람다 표현식 도입이다.
그중에서도 실무에서 자주 등장하는 인터페이스가 SupplierRunnable이다.

 

1. 함수형 인터페이스

함수형 인터페이스는 추상 메서드를 단 하나만 갖는 인터페이스이다.

예:

  • Runnable
  • Supplier<T>
  • Consumer<T>
  • Function<T, R>
  • Predicate<T>

모두 람다식으로 표현할 수 있다.

 

2. Supplier — “값을 만들어서 공급하는 인터페이스”

@FunctionalInterface
public interface Supplier<T> {
    T get();
}

✔ 주요 특징

  • 입력 인자가 없다.
  • 무언가를 생성하거나 반환하는 역할을 한다.
  • 표현식 형태:  () -> T

“값을 필요할 때 지연 생성(lazy)하여 제공하는 역할”

 

 

2-1. 간단한 예시

Supplier<String> supplier = () -> "Hello Supplier";
System.out.println(supplier.get()); // Hello Supplier

 

 

2-2. 객체 생성 캐싱 / Lazy Loading에 활용

Supplier는 지연 초기화(Lazy initialization)에 많이 사용된다.

Supplier<Connection> connectionSupplier = () -> createConnection();

Connection conn = connectionSupplier.get(); // 필요한 시점에 생성

 

 

2-3. Optional.orElseGet() 예시

Java Optional의 orElseGet()이 Supplier 기반이다.

String result = optional.orElseGet(() -> loadFromDB());

orElseGet()은 optional이 비어 있을 때만 Supplier를 실행하므로,
불필요한 DB 호출을 막는 효과가 있다.

 

2-4. 비싼 연산 지연 처리

Supplier<BigDecimal> totalPriceSupplier = () -> calculateTotalPrice();

if (needTotalPrice()) {
    BigDecimal price = totalPriceSupplier.get();
}

연산 비용이 높은 계산을 조건에 따라 수행할 때 Supplier는 매우 유용한 도구이다.

 

3. Runnable — “아무것도 반환하지 않는 작업을 수행하는 인터페이스”

@FunctionalInterface
public interface Runnable {
    void run();
}

✔ 주요 특징

  • 반환 값이 없다 (void).
  • 인자도 없다.
  • 오직 “실행할 동작(작업)” 한 가지를 표현하는 인터페이스이다.
  • 스레드와 함께 많이 사용된다.
  • 표현식 형태:  () -> void

 

3-1. Thread에서 Runnable 사용

가장 전형적인 용도는 스레드 실행이다.

Runnable task = () -> {
    System.out.println("작업 실행 중");
};

Thread thread = new Thread(task);
thread.start();

 

 

3-2. ExecutorService와 함께 사용

스레드 풀 구조에서도 Runnable은 기본이다.

ExecutorService executor = Executors.newFixedThreadPool(2);

executor.submit(() -> {
    System.out.println("비동기 작업 실행");
});

Runnable은 반환값이 필요 없는 작업에 적합하다.

 

4. Supplier, Runnable 차이점

두 인터페이스 모두 파라미터가 없다는 공통점이 있지만, 목적이 완전히 다르다.

인터페이스 역할 메서드 반환 사용하는 경우 
Supplier<T> 값을 공급 T get() 반환 O Lazy Loading, 캐싱, 팩토리 메서드, Optional.orElseGet
Runnable 작업을 실행 void run() 반환 X 스레드 실행, 비동기 작업, 이벤트 핸들러

 

Supplier는 “무언가를 반환하는 함수”

Runnable은 “반환 없이 수행하는 작업”

 

✔ 반환값이 필요하면 → Supplier

예:

  • DB에서 값을 읽어오고 싶다
  • 객체를 생성하는 함수를 전달하고 싶다
  • 값 계산을 지연 실행하고 싶다

✔ 단순 실행 작업이면 → Runnable

예:

  • 로그 기록
  • 비동기 알림 전송
  • UI 버튼 클릭 이벤트
  • 배치 작업 실행

 

6. 예시 코드 

6-1. Retry(재시도) 로직 구현

Supplier 버전 (반환값 필요)

public <T> T retry(Supplier<T> action) {
    int max = 3;
    Exception last = null;

    for (int i = 0; i < max; i++) {
        try {
            return action.get();
        } catch (Exception e) {
            last = e;
        }
    }
    throw new RuntimeException(last);
}

사용:

String data = retry(() -> loadFromRemoteApi());

 

 

Runnable 버전 (반환값 없음)

public void retry(Runnable action) {
    int max = 3;

    for (int i = 0; i < max; i++) {
        try {
            action.run();
            return;
        } catch (Exception ignored) {}
    }
}

사용:

retry(() -> sendNotification());

 

 

반응형

'IT > JAVA' 카테고리의 다른 글

CompletableFuture 비동기 처리  (0) 2026.01.02
Java 멀티스레드와 병렬 실행  (0) 2025.12.07
getOrDefault() vs computeIfAbsent()  (0) 2025.12.06
ReentrantLock 락 제어  (0) 2025.12.06
Java 예외: RuntimeException  (0) 2025.12.06