람다 표현식을 사용하는 자신만의 메서드 작성법을 알아보자.
목차
1. 지연 실행 구하기
2. 함수형 인터페이스 고르기
3. 자신만의 함수형 인터페이스 구현하기
1. 지연 실행 구하기
람다 표현식을 사용하는 이유는 지연실행이다. 당장 코드를 실행하고 싶다면 람다를 사용하지 않는다.
코드를 나중에 실행하는 이유
- 별도의 스레드에서 코드 실행
- 코드를 여러 번 수행
- 알고리즘의 올바른 지점에서 코드 실행(정렬에서의 비교연산 같은 경우)
- 어떤 일(버튼 클릭, 데이터 수진 등)이 일어날 때 코드 실행
- 필요할 때만 코드 실행
public class RepeatDemo {
public static void main(String[] args) {
repeat(10, () -> System.out.println("Hello World!"));
}
public static void repeat(int n, Runnable runnable) {
for (int i = 0; i < n; i++) {
runnable.run();
}
}
}
람다 표현식의 구현부는 runnable.run()이 호출될 때 실행된다.
int값 처리에 사용하는 표준 함수형 인터페이스인 IntConsumer로 몇 번째 반복을 수행하는지 출력한다.
public class RepeatDemo {
...
public static void main(String[] args) {
repeat(10, i -> System.out.println("Countdown : " + (9 - i)));
}
public static void repeat(int n, IntConsumer intConsumer) {
for(int i = 0; i < n; i++) {
intConsumer.accept(i);
}
}
}
2. 함수형 인터페이스 고르기
- Runnable
- 인자나 반환 값 없이 액션을 수행한다.
- run
- Supplier<T>
- T 타입 값을 공급한다.
- get
- Consumer<T>
- T 타입 값을 소비한다.
- accept
- BiConsumer<T, U>
- T와 U 타입 값을 소비한다.
- accept
- Function<T, R>
- T 타입 인자를 받는 함수다.
- apply
- BiFunction<T, U, R>
- T와 U타입 인자를 받는 함수다.
- apply
- UnaryOperator<T>
- T 타입에 작용하는 단항 연산자다.
- apply
- BinaryOperator<T>
- T 타입에 작용하는 이항 연산자다.
- apply
- Predicate<T>
- 불 값을 반환하는 함수다.
- test
- BiPredicate<T, U>
- 두 가지 인자를 받고 불 값을 반환하는 함수다.
- test
파일을 처리하는 메서드를 작성한다고 하자. 여기서 파일은 특정 기준을 만족해야 한다. 그럼 java.io.FileFilter 클래스와 Predicate<File> 중 권장하는 것은 Predicate이다. FileFilter 인스턴스를 만들어내서 유용하게 사용할 수 있는 메서드를 이미 갖추고 있는 경우를 제외하고는 표준 Predicate<File>을 사용한다.
기본 타입 int 용의 특화 버전들이 있다. 오토박싱을 줄이려면 특화버전을 사용하는 것이 좋다. Consumer<Integer> 대신 IntConsumer를 사용한다.
3. 자신만의 함수형 인터페이스 구현하기
표준 함수형 인터페이스가 적합하지 않은 상황에 놓이면 직접 인터페이스를 구현해야 한다.
예를 들어, 이미지를 색체 패턴으로 채운다고 하자. 사용자가 각 픽셀에 사용할 색을 넘겨주는 함수를 작성해야 한다. 그런데 (int, int) -> color 매핑에 해당하는 표준 타입은 없다. BiFunction<Integer, Integer, Color>를 사용할 수도 있지만, 오토박싱이 일어난다.
@FunctionalInterface
public interface PixelFunction {
Color apply(int x, int y);
}
public class ImageDemo {
public static BufferedImage createImage(int width, int height, PixelFunction f) {
BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
for (int x = 0; x < width; x++)
for (int y = 0; y < height; y++) {
Color color = f.apply(x, y);
image.setRGB(x, y, color.getRGB());
}
return image;
}
public static void main(String[] args) throws IOException {
BufferedImage frenchFlag = ImageDemo.createImage(150, 100,
(x, y) -> x < 50 ? Color.BLUE : x < 100 ? Color.WHITE : Color.RED);
Path path = Paths.get("flag.png");
ImageIO.write(frenchFlag, "PNG", path.toFile());
System.out.println("Image saved to " + path.toAbsolutePath());
}
}