JAVA/자바공부
JAVA 함수형 프로그래밍 (1) - Functional Interface
sendkite
2024. 8. 16. 03:31
- 자바에서 제공하는 함수형 프로그래밍 도구 java.util.function 패키지에 위치한 대표적인 인터페이스 사용법을 정리한다.
- 아래의 기능을 적재적소에서 활용하면 가독성, 유지보수, 확장성이 좋은 코드를 작성할 수 있다.
- 엄청 많은데 큰 분류로, Function, Functional Interface, Consumer, Supplier, Predicate, Comparator의 사용법을 알면 원시타입용도 인터페이스(박싱 안해서 메모리 덜 사용), 추가 매개변수용도 인터페이스와 같이 구분할 수 있다.

1. Function<T, R> 인터페이스
- 매개변수를 조작해서 반환값을 얻는 용도
@Test
@DisplayName("Function interface 테스트 - 매개변수가 1개")
void step1() {
// Function<T, R> - T를 받아서 R을 리턴하는 함수형 인터페이스
Function<Integer, Integer> adder = new Adder();
assertThat(adder.apply(10)).isEqualTo(20);
}
class Adder implements Function<Integer, Integer> {
@Override
public Integer apply(Integer integer) {
return integer + 10;
}
}
2. Lambda Expression
- 익명함수를 사용하면 가독성 있고 확장성 있게 쓸 수 있다.
@Test
@DisplayName("Lambda expression 테스트")
void step2() {
Function<Integer, Integer> adder = (Integer x) -> x + 10;
assertThat(adder.apply(10)).isEqualTo(20);
}
4. BiFunction<T, U , R> 인터페이스
- 매개변수가 2개인 경우 반환값 처리할때 활용
@Test
@DisplayName("BiFunction 테스트 - 매개변수가 2개")
void step3() {
// 매개변수가 2개인 경우 - BiFunction<T, U, R> - T, U를 받아서 R을 리턴하는 함수형 인터페이스
BiFunction<Integer, Integer, Integer> adder = (x, y) -> x + y;
assertThat(adder.apply(10, 10)).isEqualTo(20);
}
4. Functional Interface
- 매개변수가 2개 이상인 경우 Functional Interface를 만들어 함수형 프로그래밍을 할 수 있다.
- @FunctionalInterface란 단 1개의 abstract method를 가진 인터페이스를 말한다.
- 아래는 매개변수 3개의 Functional Interface의 예시
@Test
@DisplayName("Functional interface 테스트 - 매개변수가 3개")
void step4() {
TriFunction<Integer, Integer, Integer, Integer> adder = (x, y, z) -> x + y + z;
assertThat(adder.apply(10, 10, 10)).isEqualTo(30);
}
@FunctionalInterface // 단 1개의 abstract method 만 가지는 인터페이스
public interface TriFunction<T, U, V, R> {
R apply(T t, U u, V v);
}
5. Supplier
- 매개변수 1개를 받아서 아무것도 리턴하지 않는 void 타입의 함수형 인터페이스
@Test
@DisplayName("Functional interface 테스트 - Supplier")
void step5() {
// Supplier<T> - T를 리턴하는 함수형 인터페이스
Supplier<String> supplier = () -> "Hello, World!";
assertThat(supplier.get()).isEqualTo("Hello, World!");
}
6. Consumer
- 매개변수 1개를 받아서 아무것도 리턴하지 않는 void 타입의 함수형 인터페이스
- 앞서 언급한 함수형 인터페이스는 매개변수로 전달하여 추가 작업을 해, 확장성 좋은 코드를 짤 수 있다.
@Test
@DisplayName("Functional interface 테스트 - Consumer")
void step6() {
// Consumer<T> - T를 받아서 아무것도 리턴하지 않는 함수형 인터페이스
Consumer<String> helloConsumer = (String s) -> System.out.println(s);
helloConsumer.accept("Hello, World!");
Consumer<Integer> integerPrinter = (Integer i) -> System.out.println("input: " + i);
Consumer<Integer> temMultiplyPrinter = (Integer i) -> System.out.println(i * 10);
// 다형성 활용 - Consumer<Integer> 전달해서 확장성 있는 코드 작성 가능
process(List.of(1, 2, 3), temMultiplyPrinter);
}
static <T> void process(List<T> inputs, Consumer<T> processor) {
for (T input : inputs) {
processor.accept(input);
}
}
7. BiConsumer
- 매개변수 2개를 받아서 아무것도 리턴하지 않는 void 타입의 함수형 인터페이스
@Test
@DisplayName("Functional interface 테스트 - BiConsumer")
void step7() {
// BiConsumer<T, U> - T, U를 받아서 아무것도 리턴하지 않는 함수형 인터페이스
BiConsumer<Integer, Double> printer = (x, y) -> System.out.println("x: " + x + ", y: " + y);
printer.accept(10, 10.0);
}
8. Predicate
- 매개변수 2개를 받아서 boolean 값을 리턴하는 함수형 인터페이스.
- QueryDsl의 BooleanBuiler를 쓸때의 그것
@Test
@DisplayName("Functional interface 테스트 - Predicate")
void step8() {
// Predicate<T> - T를 받아서 boolean 을 리턴하는 함수형 인터페이스
Predicate<Integer> isEven = (Integer x) -> x % 2 == 0;
assertThat(isEven.test(10)).isTrue();
assertThat(isEven.test(11)).isFalse();
// Predicate 기본 함수 사용
Predicate<Integer> isPositive = (Integer x) -> x > 0;
Predicate<Integer> isNegative = (Integer x) -> x < 0;
Predicate<Integer> isZero = (Integer x) -> x == 0;
assertThat(isPositive.and(isNegative).test(10)).isFalse();
assertThat(isPositive.and(isNegative).test(-10)).isFalse();
assertThat(isPositive.and(isNegative).test(0)).isFalse();
assertThat(isPositive.or(isNegative).test(10)).isTrue();
assertThat(isPositive.or(isNegative).test(-10)).isTrue();
assertThat(isPositive.or(isNegative).test(0)).isFalse();
assertThat(isPositive.negate().test(10)).isFalse();
assertThat(isPositive.negate().test(-10)).isTrue();
assertThat(isPositive.negate().test(0)).isTrue();
assertThat(isZero.negate().test(10)).isTrue();
assertThat(isZero.negate().test(-10)).isTrue();
assertThat(isZero.negate().test(0)).isFalse();
}
9. Comparator
- 매개변수를 받아서 int를 리턴하는 함수형 인터페이스이다.
- a와 b 2개의 값을 비교해서 작으면 음수, 크면 양수를 리턴한다.
- 아래는 이름 비교를 사용한 정렬 구현이다.
@Test
@DisplayName("Functional interface 테스트 - Comparator")
void step9() {
// Comparator<T> - T를 받아서 int 를 리턴하는 함수형 인터페이스
// compare(T o1, T o2) - o1이 o2보다 작으면 음수, 같으면 0, 크면 양수 리턴
// given
User user1 = User.create("hello@hello.com", "hello12", "def");
User user2 = User.create("hello@hello.com", "hello123", "abc");
List<User> userList = Arrays.asList(user1, user2);
assertThat(userList.get(0)).isEqualTo(user1);
// when
Collections.sort(userList, (u1, u2) -> u1.getName().compareTo(u2.getName()));
// then
assertThat(userList.get(0)).isEqualTo(user2);
assertThat(userList.get(1)).isEqualTo(user1);
}
반응형