본문 바로가기
카테고리 없음

동작 파라미터화 실전 정리

by sujupark54 2026. 2. 13.

동작 파라미터화

시작에 앞서: 실행 환경

본 글의 모든 코드는 아래 환경에서 컴파일 및 런타임 테스트를 완료했다. 환경 차이로 인한 혼란을 줄이기 위해 버전 정보를 먼저 명확히 한다.


Java: 21
Launcher JVM: 21.0.5 (Amazon Corretto)

$ java -version
openjdk version "21.0.5" 2024-10-15 LTS
OpenJDK Runtime Environment Corretto-21.0.5.11.1

모든 예제는 추가 설정 없이 정상적으로 동작한다.


요구사항과 문제의 본질

주어진 요구사항은 단순하다. 바나나 목록에서 원하는 조건을 만족하는 바나나만 필터링하고 싶다.

하지만 조건은 계속 늘어난다.

  • 빨간색 바나나만 찾고 싶다
  • 초록색 바나나만 찾고 싶다
  • 무거운 바나나만 찾고 싶다
  • 가벼운 바나나만 찾고 싶다
  • x 조건 또는 y 조건을 만족하고 싶다
  • x, y, z 여러 조건을 동시에 만족하고 싶다

이 요구사항을 그대로 코드로 옮기면 조건마다 메서드가 하나씩 늘어난다.

처음에는 단순해 보이지만 조건이 추가될수록 클래스는 비대해지고 기존 메서드를 수정하거나 새 메서드를 계속 추가해야 한다.

이 문제의 본질은 “조건이 바뀐다”는 데 있다.


동작 파라미터화란 무엇인가

객체지향 패러다임에서 중요한 개념 중 하나는 추상화다.

추상화란 변하지 않는 것과 변하는 것을 분리하는 작업이다.

객체뿐 아니라 행위 역시 추상화의 대상이 될 수 있다.

Java 8부터 도입된 동작 파라미터화는 “행위를 값처럼 전달”하는 방식이다.

아직 어떻게 실행될지 정해지지 않은 동작을 매개변수로 전달하고 실제 실행 시점에 그 동작을 결정한다.

즉, 무엇을 할지는 외부에서 결정하고
어떻게 반복할지는 내부에서 유지한다.

이 개념이 적용되면 기존 코드를 수정하지 않고도 새로운 요구사항에 대응할 수 있다.


동작 파라미터화로 바나나 필터링하기

기존 방식은 조건마다 메서드를 만든다.


public List<Banana> filterRedBananas(List<Banana> list) {
    return list.stream()
        .filter(banana -> banana.color().equals(Color.RED))
        .toList();
}

이 방식은 조건이 늘어날수록 메서드도 함께 늘어난다.

이를 하나의 메서드로 일반화하면 다음과 같다.


public List<Banana> filteredBananas(
        List<Banana> list,
        Predicate<Banana> condition
) {
    return list.stream()
        .filter(condition)
        .toList();
}

Predicate<Banana>는 “바나나가 조건을 만족하는가”라는 행위를 추상화한 매개변수다.

이제 조건은 메서드 밖에서 결정된다.


filteredBananas(list, b -> b.color().equals(Color.RED));
filteredBananas(list, b -> b.weight().equals(Weight.HEAVY));
filteredBananas(list, b ->
    b.color().equals(Color.GREEN) &&
    b.weight().equals(Weight.LIGHT)
);

n개의 조건이 추가되더라도 메서드는 바뀌지 않는다.


함수형 인터페이스와 Predicate

Predicate는 java.util.function 패키지에 기본 제공되는 함수형 인터페이스다.


@FunctionalInterface
public interface Predicate<T> {
    boolean test(T t);
}

단 하나의 추상 메서드만을 가지며 boolean을 반환한다.

Stream의 filter 메서드는 Predicate를 받아 동작 파라미터화를 실현한다.

람다 표현식이나 메서드 참조를 사용하면 코드는 더욱 간결해진다.


private static Predicate<Banana> greenCondition() {
    return b -> b.color().equals(Color.GREEN);
}

의도가 드러나는 메서드명은 가독성을 크게 높여준다.


정리하며

동작 파라미터화는 조건 분기 코드를 제거하고 확장에 열린 구조를 만든다.

변경되는 것은 외부로 밀어내고 변하지 않는 흐름은 내부에 둔다.

Java의 함수형 인터페이스와 람다 표현식은 이 개념을 자연스럽게 구현할 수 있도록 돕는다.

작은 예제처럼 보이지만 실제 서비스 코드에서도 유지보수성과 확장성을 크게 향상시킬 수 있는 중요한 설계 기법이다.