λ³Έλ¬Έ λ°”λ‘œκ°€κΈ°
개발/Java

[JAVA 8] ν•¨μˆ˜ν˜• μΈν„°νŽ˜μ΄μŠ€(Functional Interface)

by 1mj 2022. 1. 14.

ν•¨μˆ˜ν˜• μΈν„°νŽ˜μ΄μŠ€(Functional Interface)

μ—¬λŸ¬ 개의 λ””ν΄νŠΈ λ©”μ„œλ“œμ™€λŠ” 상관없이 좔상 λ©”μ„œλ“œκ°€ 였직 ν•˜λ‚˜μΈ ν•¨μˆ˜ν˜• μΈν„°νŽ˜μ΄μŠ€μ΄λ‹€.

λžŒλ‹€μ‹μ€ ν•¨μˆ˜ν˜• μΈν„°νŽ˜μ΄μŠ€λ₯Ό 기반으둜만 μž‘μ„±λ  수 μžˆλ‹€.

🧐 μΈν„°νŽ˜μ΄μŠ€ 및 좔상 ν΄λž˜μŠ€μ™€ 좔상 λ©”μ„œλ“œ
μΈν„°νŽ˜μ΄μŠ€μ™€ 좔상 ν΄λž˜μŠ€λŠ” 상속(extends) λ°›κ±°λ‚˜ κ΅¬ν˜„(implements)ν•˜λŠ” ν΄λž˜μŠ€κ°€ μΈν„°νŽ˜μ΄μŠ€λ‚˜ 좔상 클래슀 λ‚΄ 좔상 λ©”μ„œλ“œλ₯Ό κ΅¬ν˜„ν•˜λ„λ‘ κ°•μ œν•œλ‹€.
- μΈν„°νŽ˜μ΄μŠ€ (λ‹€ν˜•μ„±μ˜ νŠΉμ§•)
곡톡 κΈ°λŠ₯이 ν•„μš”ν•  λ•Œ 좔상 λ©”μ„œλ“œλ₯Ό μ •μ˜ν•΄λ†“κ³  κ΅¬ν˜„ν•˜λŠ” ν΄λž˜μŠ€μ—μ„œ 각 κΈ°λŠ₯을 μ˜€λ²„λΌμ΄λ”© ν•˜μ—¬ μ—¬λŸ¬ ν˜•νƒœ, κΈ°λŠ₯으둜 κ΅¬ν˜„ν•  수 μžˆλ‹€.
- 좔상 클래슀 (μƒμ†μ˜ νŠΉμ§•)
상속 κ΄€κ³„μ—μ„œ 같은 λΆ€λͺ¨ 좔상 클래슀λ₯Ό μƒμ†λ°›λŠ” μžμ‹ 클래슀 간에 곡톡 κΈ°λŠ₯을 각각 κ΅¬ν˜„ν•˜κ³  ν™•μž₯μ‹œν‚¨λ‹€.
κ·Έ μžμ²΄λ‘œλŠ” 클래슀의 역할을 λ‹€ ν•˜μ§€ λͺ»ν•˜μ§€λ§Œ μƒˆλ‘œμš΄ 클래슀λ₯Ό μž‘μ„±ν•˜λŠ”λ° 바탕이 되며 ν•˜λ‚˜ μ΄μƒμ˜ 좔상 λ©”μ†Œλ“œλ₯Ό 가지고 μžˆλ‹€.
- 좔상 λ©”μ„œλ“œ
λ©”μ„œλ“œμ˜ μ„ μ–ΈλΆ€λ§Œ μž‘μ„±ν•˜κ³  κ΅¬ν˜„λΆ€λŠ” μž‘μ„±ν•˜μ§€ μ•Šμ€ μ±„λ‘œ 남겨두어 상속 λ°›λŠ” ν΄λž˜μŠ€μ—μ„œ κ΅¬ν˜„ν•˜λ„λ‘ ν•œλ‹€.

 

ν•¨μˆ˜ν˜• μΈν„°νŽ˜μ΄μŠ€ λ§Œλ“€κΈ°

ν•¨μˆ˜ν˜• μΈν„°νŽ˜μ΄μŠ€λŠ” ν•˜λ‚˜μ˜ 좔상 λ©”μ„œλ“œλ₯Ό κ°€μ Έμ•Ό ν•˜μ§€λ§Œ, μ—¬λŸ¬ 개의 static λ©”μ„œλ“œμ™€ defaultλ₯Ό μ •μ˜ν•  수 μžˆλ‹€.

@FunctionalInterface μ–΄λ…Έν…Œμ΄μ…˜μ€ ν•¨μˆ˜ν˜• μΈν„°νŽ˜μ΄μŠ€μ˜ 쑰건에 λΆ€ν•©ν•˜λŠ”μ§€ ν™•μΈν•˜μ—¬ λ‘˜ μ΄μƒμ˜ 좔상 λ©”μ„œλ“œκ°€ μ‘΄μž¬ν•˜λ©΄ 컴파일 였λ₯˜λ₯Ό λ°œμƒμ‹œν‚¨λ‹€.

 

@FunctionalInterface
public interface printerInterface<T> {
	T printSomething();	// 좔상 λ©”μ„œλ“œ
    static void printName() {
    	System.out.println("Kuromi");
    }
    default void printAge() {
    	System.out.println("10");
    }
}


// μ‹€μ œλ‘œ μ‚¬μš©ν•  클래슀 λ‚΄ κ΅¬ν˜„
printerInterface<String> printerInterface = () -> "hello";
System.out.println(printerInterface.printSomething());
printerInterface.printName();
printerInterface.printAge();

 

기본적으둜 μ œκ³΅ν•˜λŠ” ν•¨μˆ˜ν˜• μΈν„°νŽ˜μ΄μŠ€

java.lang.function νŒ¨ν‚€μ§€μ— javaμ—μ„œ 기본으둜 μ œκ³΅ν•˜λŠ” ν•¨μˆ˜ν˜• μΈν„°νŽ˜μ΄μŠ€κ°€ 미리 μ •μ˜λ˜μ–΄ μžˆλ‹€.

μ’…λ₯˜ 인자 λ°˜ν™˜ λ©”μ„œλ“œ μ„€λͺ…
Runnable     void run() 기본적인 ν˜•νƒœμ˜ μΈν„°νŽ˜μ΄μŠ€, μΈμžμ™€ λ°˜ν™˜κ°’ λͺ¨λ‘ μ—†μŒ
Supplier<T>   <T> T get() μΈμžκ°€ μ—†μ΄ μ œλ„ˆλ¦­ νƒ€μž…μ˜ λ°˜ν™˜κ°’λ§Œ μžˆλŠ” μΈν„°νŽ˜μ΄μŠ€, ν•­μƒ κ°™μ€ κ°’을 λ°˜ν™˜
Consumer<T> <T>   void accept(T t) μ œλ„ˆλ¦­ νƒ€μž…μ˜ μΈμžλ§Œ μžˆκ³  λ°˜ν™˜κ°’이 μ—†λŠ” μΈν„°νŽ˜μ΄μŠ€
Predicate<T> <T> Boolean boolean test(T t) μ œλ„ˆλ¦­ νƒ€μž…μ˜ μΈμžμ™€ Boolean νƒ€μž…μ˜ λ°˜ν™˜κ°’을 κ°€μ§€λŠ” μΈν„°νŽ˜μ΄μŠ€
Function<T, R> <T>  <R> R apply(T t) μ œλ„ˆλ¦­ νƒ€μž…μ˜ μΈμžμ™€ λ‹€λ₯Έ μ œλ„ˆλ¦­ νƒ€μž…μ˜ λ°˜ν™˜κ°’이 κ°™μ΄ μžˆλŠ” μΈν„°νŽ˜μ΄μŠ€
UnaryOperator<T> <T> <T> T apply(T t) 같은 μ œλ„ˆλ¦­ νƒ€μž…μ˜ μΈμžμ™€ λ°˜ν™˜κ°’을 κ°€μ§€κ³  μžˆλŠ” μΈν„°νŽ˜μ΄μŠ€
BinaryOperator<T> <T, T> <T> R apply(T t, U u) 같은 μ œλ„ˆλ¦­ νƒ€μž…μ˜ μΈμž 2개λ₯Ό λ°›κ³  κ°™μ€ μ œλ„ˆλ¦­ νƒ€μž…μ˜ λ°˜ν™˜κ°’을 κ°€μ§€λŠ” μΈν„°νŽ˜μ΄μŠ€
BiConsumer<T, U> <T, U>   void accept(T t, U u) λ‹€λ₯Έ μ œλ„ˆλ¦­ νƒ€μž…μ˜ μΈμž 2개λ₯Ό λ°›κ³  λ°˜ν™˜κ°’이 μ—†λŠ” μΈν„°νŽ˜μ΄μŠ€
BiPredicate<T, U> <T, U> Boolean boolean test(T t, U u) λ‹€λ₯Έ μ œλ„ˆλ¦­ νƒ€μž…μ˜ μΈμž 2개λ₯Ό λ°›κ³  Boolean νƒ€μž…μ˜ λ°˜ν™˜κ°’을 κ°€μ§€λŠ” μΈν„°νŽ˜μ΄μŠ€
BiFunction<T, U, R> <T, U> <R> R apply(T t, U u) λ‹€λ₯Έ μ œλ„ˆλ¦­ νƒ€μž…μ˜ μΈμž 2개λ₯Ό λ°›κ³  λ‹€λ₯Έ μ œλ„ˆλ¦­ νƒ€μž…μ˜ λ°˜ν™˜κ°’을 κ°€μ§€λŠ” μΈν„°νŽ˜μ΄μŠ€
Comparator<T> <T, U> int   같은 μ œλ„ˆλ¦­ νƒ€μž…μ˜ μΈμž 2개λ₯Ό λ°›κ³  Integer λ°˜ν™˜κ°’을 κ°€μ§€λŠ” μΈν„°νŽ˜μ΄μŠ€, κ°μ²΄κ°„μ˜ κ°’을 λΉ„κ΅ν•˜κΈ° μœ„ν•œ compare κΈ°λŠ₯을 μœ„ν•œ μΈν„°νŽ˜μ΄μŠ€

 

ν•¨μˆ˜ν˜• μΈν„°νŽ˜μ΄μŠ€ μ‚¬μš© 예제

1. Predicate : T → boolean

인자 ν•˜λ‚˜λ₯Ό λ°›μ•„μ„œ boolean νƒ€μž…μ„ λ¦¬ν„΄ν•œλ‹€.

public interface Predicate<T> {
    boolean test(T t);
    ....
}
import java.util.function.Predicate;

public class Example {
    public static void main(String[] args) {
        Predicate<Integer> predicate1 = (num) -> num > 0;
        System.out.println(predicate1.test(100));	// true
        
        Predicate<Integer> predicate2 = (num) -> num < 100;
        System.out.println(predicate1.and(predicate2).test(100));	// false
        System.out.println(predicate1.or(predicate2).test(100));	// true
    }
}

 

2. Consumer : T → void

인자 ν•˜λ‚˜λ₯Ό λ°›κ³  아무 것도 λ¦¬ν„΄ν•˜μ§€ μ•ŠλŠ”λ‹€.

@FunctionalInterface
public interface Consumer<T> {
    void accept(T t);
}
import java.util.function.Consumer;
import java.util.Arrays;
import java.util.List;

public class Example {
    public static void main(String[] args) {
        Consumer<String> consumer = s -> System.out.println(s.toUpperCase());
        consumer.accept("hello world");	// HELLO WORLD
        List<String> list = Arrays.asList("hello", "world");
        list.forEach(consumer);	// HELLO, WORLD
    }
}

 

3. Supplier : () → T

아무 것도 μž…λ ₯ 받지 μ•Šκ³  T νƒ€μž…μ˜ 객체λ₯Ό λ¦¬ν„΄ν•œλ‹€.

public interface Supplier<T> {
    T get();
}
import java.util.function.Supplier;

public class Example {
    public static void main(String[] args) {
        Supplier<String> supplier= () -> "HelloWorld";
        System.out.println(supplier.get());	// HelloWorld
    }
}

 

4. Function : T → R

T νƒ€μž… 인자λ₯Ό λ°›μ•„ R νƒ€μž…μ„ λ¦¬ν„΄ν•œλ‹€.

public interface Function<T, R> {
    R apply(T t);
}
import java.util.function.Function;

public class Example {
    public static void main(String[] args) {
        Function<Integer, Integer> func1 = n -> n * 10;	// 10λ°°ν•œ κ°’
        System.out.println(func1.apply(3));	// 30
        
        Function<Integer, String> func2 = n -> "RESULT: " + n;	// λ¬Έμžμ—΄λ‘œ λ³€κ²½
        String result = func1.andThen(func2).apply(3);	// func1 λ¨Όμ € μ‹€ν–‰ ν›„ κ²°κ³Όκ°€ func2둜 전달
        System.out.println(result);	// RESULT: 30
    }
}

 

참고자료 및 좜처 πŸ™‡‍♂️

https://bcp0109.tistory.com/313

https://codechacha.com/ko/java8-predicate-example/

https://jogeum.net/18

https://zzang9ha.tistory.com/303

https://ykh6242.tistory.com/112

https://bcp0109.tistory.com/313

λŒ“κΈ€