Java Functional Interface 알짜만 빼먹기 Predicate/Spplier/Consumer/Function
Functional Interface 정의
Functional Interface 는 구현해야하는 abstract method가 한 개만 정의되어 있는 Interface를 말합니다.
public interface TestInterface {
public String getName();
}
Java에서는 위와 같이 메소드가 하나만 있는 Interface를 Functional Interface 로 인식합니다.
하지만 여러 사람이 개발하다보면 실수로 메소드를 추가할 수 있기 때문에
@FunctionalInterface annotation을 붙여주는게 좋습니다. (물론 추가 시 컴파일 에러 발생)
@FunctionalInterface
public interface TestInterface {
public String getName();
}
Functional Interface가 메소드가 한개만 정의되어 있는 Interface를 말한다고 했지만,
default method나 static method는 여러개 정의 하여도 문제가 되지 않습니다.
@FunctionalInterface
public interface TestInterface {
public String getName();
default void printDefault() {
System.out.println("aljjabaegi-default");
}
default void printDefault2() {
System.out.println("aljjabaegi-default2");
}
static void printStatic() {
System.out.println("aljjabaegi-static");
}
static void printStatic2() {
System.out.println("aljjabaegi-static2");
}
}
Functional Interface 등장 이유
기존에 Interface는 implements 받은 class에서 메소드를 구현하여 사용하였습니다.
public class TestImple implements TestInterface{
@Override
public String getName() {
return "aljjabaegi";
}
}
public class FunctionTest {
public static void main(String args[]){
TestImple ti = new TestImple();
System.out.println(ti.getName());
ti.printDefault();
TestInterface.printStatic();
}
}
하지만 람다식을 사용하면 implements 하는 class를 생성하지 않고
보다 간결하게 메소드를 정의하여 사용할 수 있습니다.
(default, static method도 그대로 사용 가능)
public class FunctionTest {
public static void main(String args[]){
TestInterface tf = () -> "aljjabaegi";
System.out.println(tf.getName());
tf.printDefault();
TestInterface.printStatic();
}
}
Functional Interface 종류
java.util.function 에서는 다양한 종류의 Functional Interface를 제공합니다. (아래 Link 참고)
Link : https://docs.oracle.com/javase/8/docs/api/java/util/function/package-summary.html
이 중에 대표적인 4개의 Functional Interface를 알아보겠습니다.
Predicate<T>
Predicate 는 객체를 비교할 때 사용하고, boolean을 리턴합니다.
Predicate<String> strContain = (str) -> str.contains("aljja");
Predicate<String> strStartsWidth = (str) -> str.startsWith("http");
String url = "aljjabaegi.tistory.com";
boolean containResult = strContain.test(url);
System.out.println(containResult); /** true */
boolean startsWithResult = strStartsWidth.test(url);
System.out.println(startsWithResult); /** false */
test() 종단연산 메소드를 사용해서 비교 결과를 리턴받을 수 있습니다.
and(), or(), negate() 중개연산 default 메소드를 제공하며 이를 사용하여 복수의 조건을 추가할 수 있습니다.
이 외에도 isEqual(), not() static 메소드가 구현되어 있습니다.
Predicate<String> strContain = (str) -> str.contains("aljja");
Predicate<String> strStartsWidth = (str) -> str.startsWith("http");
Predicate<String> strEndsWidth = (str) -> str.endsWith("com");
String url = "aljjabaegi.tistory.com";
boolean result = strContain.or(strStartsWidth).and(strEndsWidth).negate().test(url);
System.out.println(result); /** false */
Supplier<T>
Supplier는 새로운 값을 생성할 때 사용하고 선언된 타입(T)으로 리턴을 합니다.
method는 값을 얻는 get() 이 있습니다.
int num = 10;
Supplier<Integer> plusTen = () -> num+10;
System.out.println(plusTen.get()); /** 20 */
Consumer<T>
Consumer는 Supplier와 반대로 파라메터가 있고, 리턴값 없습니다.
파라미터를 받아서 소비하고 끝낼 때 사용합니다.
method는 파라미터를 받는 accept() 가 있고,
default method는 다수의 Consumer를 연결해 수행하는 andThen()이 있습니다.
Consumer<Integer> minusTen = (number) -> System.out.println(number - 10);
Consumer<Integer> timesTen = (number) -> System.out.println(number*10);
timesTen.andThen(minusTen).accept(10); /** 100 (andThen ->) 0*/
timesTen 실행 후 minusTen이 실행됩니다. (timesTen.accept(10); -> minusTen.aceppt(10);)
Function<T, R>
Function은 한개의 파라메터(T - 파라메터타입)와 한개의 리턴값(R - 리턴타입)이 있습니다.
파라미터를 받아서 로직 수행 후 리턴해야 할 때 사용합니다.
method는 apply() 가 있고
default method는 andThen() (Consumer 와 동일 기능) 과
compose() (andThen()과 순서만 다름) 가 있습니다.
static method는 파라메터를 그대로 리턴하는 identity()가 있습니다.
Function<String, Integer> strToInt = (string) -> Integer.valueOf(string);
Function<Integer, String> intToStr = (number) -> String.valueOf(number);
int intNum = intToStr.andThen(strToInt).apply(10);
System.out.println(intNum);
Function<Integer, Integer> strNum = strToInt.compose(intToStr);
int intNum2 = strNum.apply(10);
System.out.println(intNum2);
Function<Integer, Integer> identity = Function.identity();
System.out.println(identity.apply(10));
Function Interface를 함수형 프로그래밍, 스트림, 람다식을 쓰려면 반드시 알아야 되는 부분입니다.
다음 포스팅은 스트림이 될 예정이며,
Functional Interface를 같이 활용해 보도록 하겠습니다.
'Programing > JAVA' 카테고리의 다른 글
Java List<?> 정렬, 다중조건정렬, 오름, 내림차순 Comparator (0) | 2023.01.25 |
---|---|
Custom Annotation 생성하기 @interface 알짜만 빼먹기 (0) | 2022.11.15 |
Java Optional 알짜만 빼먹기 사용법/등장이유 (1) | 2022.10.03 |
Java Collection 반복문 정리 for, while, iterator, stream (0) | 2022.09.29 |
Java GC Gargabe Collection 알짜만 빼먹기 / 알고리즘 / 종류 / 모니터링 VisualVM (1) | 2022.05.12 |
댓글