Programing/JAVA

Java Functional Interface 알짜만 빼먹기 Predicate/Spplier/Consumer/Function

리커니 2022. 10. 5.
반응형

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

 

java.util.function (Java Platform SE 8 )

Interface Summary  Interface Description BiConsumer Represents an operation that accepts two input arguments and returns no result. BiFunction Represents a function that accepts two arguments and produces a result. BinaryOperator Represents an operation u

docs.oracle.com

 

이 중에 대표적인 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를 같이 활용해 보도록 하겠습니다.

반응형

댓글

💲 추천 글