우리는 어떤 상황에서 일을 하든 소비자 요구사항은 항상 바뀐다. 변화는 불가피하다.

동작 파라미터화는 자주 바뀌는 요구사항에 효과적으로 대응할 수 있다. 동작 파라미터화는 아직은 어떻게 실행할 것인지 결정하지 않은 코드 블록을 의미합니다.

동작 파라미터화 예제

public class App {
    public static void main(String[] args) {
        Apple apple = new Apple(150L, Color.GREEN);
        Apple apple2 = new Apple(120L, Color.GREEN);
        Apple apple3 = new Apple(120L, Color.RED);

        List<Apple> inventory = List.of(apple, apple2, apple3);

        List<Apple> greenApples = filter(inventory, (apple1 -> apple1.color().equals(Color.GREEN)));
        greenApples.forEach(a -> System.out.println(prettyPrintApple(a, a2 -> "A " + (a2.weight() > 150 ? "heavy" : "light") + " " + a2.color() + " apple")));

    }

    public static <T> List<T> filter(List<T> list, Predicate<T> p) {
        return list.stream()
                .filter(p)
                .toList();
    }

}

코드 전달의 개념을 더욱 확실히 익힐 수 있도록 아래 예제들이 있습니다.

Comparator로 정렬하기

public class Comparator {
    public static void main(String[] args) {
        List<Apple> apples = List.of(new Apple(100L, Color.RED), new Apple(300L, Color.RED), new Apple(150L, Color.GREEN));
        List<Apple> inventory = new ArrayList<>(apples);
        inventory.sort((a1, a2) -> a1.weight().compareTo(a2.weight()));
        inventory.forEach(System.out::println);
    }
}

Runnable로 코드 블록 실행하기

자바 스레드를 이용하면 병렬로 코드 블록을 실행할 수 있다. 어떤 코드를 실행할 것인지 스레드에게 알려줄 수 있을까?

public class RunnableExample {
  public static void main(String[] args) {
    Thread t = new Thread(new Runnable() {
      @Override
      public void run() {
        System.out.println("Hello from a thread!");
      }
    });
    t.run();
  }
}
public class RunnableExample {
    public static void main(String[] args) {
        Thread t = new Thread(() -> System.out.println("Hello from a thread!"));
        t.run();
    }
}

Callable을 결과로 반환하기

ExecutorService를 이용하면 Callable 인터페이스를 이용해 Task를 스레드 풀로 보내고 결과를 Future로 저장할 수 있습니다. 이 점이 Runnable과 가장 큰 차이점입니다.

public class CallableExample {
    public static void main(String[] args) {
        ExecutorService executorService = Executors.newCachedThreadPool();
        Future<String> future = executorService.submit(new Callable<String>() {
            @Override
            public String call() throws Exception {
                return "Hello from Callable!";
            }
        });

        try {
            String result = future.get();
            System.out.println(result);
            executorService.shutdown();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
public class CallableExample {
    public static void main(String[] args) {
        ExecutorService executorService = Executors.newCachedThreadPool();
        Future<String> future = executorService.submit(() -> "Hello from Callable!");

        try {
            String result = future.get();
            System.out.println(result);
            executorService.shutdown();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

정리 📚

동작파라미터화란 메서드 내부적으로 다양한 동작을 수행할 수 있도록 코드를 메서드 인수로 전달한다. 코드전달기법을 이용하면 동작을 메서드의 인수로 전달할 수 있다.

댓글남기기