
동작 파라미터화 를 이용하면 자주 바뀌는 요구사항에 효과적으로 대응할 수 있다.
enum Color { RED, GREEN }
public static List<Apple> filterGreenApples(List<Apple> inventory) {
List<Apple> result = new ArrayList<>(); // 사과 누적 리스트
for (Apple apple: inventory) {
if (GREEN.equals(apple.getColor)) { // 녹색 사과만 선택
result.add(apple);
}
}
return result;
}
public static List<Apple> filterAppleByColor(List<Apple> inventory, Color color) {
List<Apple> result = new ArrayList<>();
for (Apple apple: inventory) {
if (apple.getColor().equals(color)) {
result.add(apple);
}
}
return result;
}
List<Apple> greenApples = filterAppleByColor(inventory, GREEN);
List<Apple> redApples = filterAppleByColor(inventory, RED);
public static List<Apple> filterAppleByWeight(List<Apple> inventory, int weight) {
List<Apple> result = new ArrayList<>();
for (Apple apple: inventory) {
if (apple.getWeight() > weight) {
result.add(apple);
}
}
return result;
}
목록을 검색하고, 각 사과에 필터링 조건을 적용하는 부분의 코드가 색 필터링 하는 코드와 대부분 중복된다. ➡️ DRY(don't repeat yourself) 원칙 어김
public static List<Apple> filterApples(List<Apple> inventory, Color color, int weight, boolean flag) {
List<Apple> result = new ArrayList<>();
for (Apple apple: inventory) {
// 색이나 무게를 선택하는 방법이 마음에 들지 않는다!!
if ((flag && apple.getColor().equals(color)) ||
(!flag && apple.getWeight() > weight)) {
result.add(apple);
}
}
return result;
}
List<Apple> greenApples = filterApples(inventory, GREEN, 0, true);
List<Apple> heavyApples = filterApples(inventory, null, 150, false);
true와 falsepublic interface ApplePredicate {
boolean test(Apple apple);
}
<무거운 사과만 선택>
publc class AppleHeavyWeightPredicate implements ApplePredicate {
public boolean test(Apple apple) {
return apple.getWeight() > 150;
}
}
<녹색 사과만 선택>
public class AppleGreenColorPredicate implements ApplePredicate {
public boolean test(Apple apple) {
return GREEN.equals(apple.getColor());
}
}

filter 메서드가 다르게 동작할 것이라고 예상할 수 있다.ApplePredicate가 알고리즘 패밀리AppleHeavyWeightPredicate와 AppleGreenColorPredicate가 전략public static List<Apple> filterApples(List<Apple> inventory, ApplePredicate p) {
List<Apple> result = new ArrayList<>();
for (Apple apple: inventory) {
if (p.test(apple)) {
result.add(apple);
}
}
}
ApplePredicate 객체에 의해 filterApples 메서드의 동작이 결정filterApples 메서드의 동작을 파라미터화한 것이다.
test 메서드test 메서드를 ApplePredicate 객체로 감싸서 전달해야 한다.ApplePredicate 클래스를 정의하지 않고 전달
List<Apple> redApples = filterApples(inventory, new ApplePredicate() { // filterApples 메서드의 동작을 직접 파라미터화했다!
public boolean test(Apple apple) {
return RED.equals(apple.getColor());
}
});
return 부분만 있어도 충분List<Apple> result = filterApples(inventory, (Apple apple) -> RED.equals(apple.getColor()));

public interface Predicate<T> {
boolean test(T t);
}
public static <T> List<T> filter(List<T> list, Predicate<T> p) {
List<T> result = new ArrayList<>();
for (T e: list) {
if (p.test(e)) {
result.add(e);
}
}
return result;
}
List<Apple> redApples = filter(inventory, (Apple apple) -> RED.equals(apple.getColor()));
List<Integer> evenNumbers = filter(number, (Integer i) -> i % 2 == 0);
Comparator로 정렬하기Runnable로 코드 블록 실행하기Callable을 결과로 반환하기java.util.Comparator 객체를 이용해서 sort의 동작을 파라미터화할 수 있다.// java.util.Comparator
public interface Comparator<T> {
int compare(T o1, T o2);
}
<익명 클래스를 이용해서 무게가 적은 순서로>
inventory.sort(new Comparator<Apple>() {
public int compare(Apple a1, Apple a2) {
return a1.getWeight().compareTo(a2.getWeight());
}
});
<람다 표현식 사용>
inventory.sort((Apple a1, Apple a2) -> a1.getWeight().compareTo(a2.getWeight()));
Thread 생성자에 객체만을 전달할 수 있었음.void run 메소드를 포함하는 익명 클래스가 Runnable 인터페이스를 구현하도록 하는 것이 일반적인 방법이었다.// java.lang.Runnable
public interface Runnable {
void run();
}
Runnable을 이용해서 다양한 동작을 스레드로 실행할 수 있다.Thread t = new Thread(new Runnable() {
public void run() {
System.out.println("Hello world");
}
});
<람다 표현식>
Thread t = new Thread(() -> System.out.println("Hello World"));
Callable 인터페이스를 이용해 결과를 반환하는 태스크를 만든다.Runnable의 업그레이드 버전이라고 생각할 수 있음// java.util.concurrent.Callable
public interface Callabe<V> {
V call();
}
ExecutorService executorService = Executor.newCachedThreadPool();
Future<String> threadName = executorService.submit(new Callable<String>() {
@Override
public String call() throws Exception {
return Thread.currentThread().getName();
}
});
<람다 사용>
Future<String> threadName = executorService.submit(() -> Thread.currentThread().getName());
Button button = new Button("Send");
button.setOnAction(new EventHandler<ActionEvent>() {
public void handle(ActionEvent event) {
label.setText("Sent!");
}
});
EventHandler는 setOnAction 메서드의 동작을 파라미터화한다.<람다 표현식>
button.setOnAction((ActionEvent event) -> label.setText("Sent!"));