함수형 인터페이스란?
- 함수형 인터페이스는 말 그대로 Java의 interface 이다.
- 함수형 인터페이스는 단 하나의 추상 메서드만 가지고 있는 인터페이스이다.(예외 : 디폴트 메서드는 포함할 수 있음)
- 함수형 인터페이스의 메서드를 람다 표현식으로 작성해서 다른 메서드의 파라미터로 전달할 수 있다.
- 즉, 람다 표현식 전체를 해당 함수형 인터페이스를 구현한 클래스의 인스턴스로 취급한다.
- Java 8에서 새롭게 추가된 함수형 인터페이스 외에 기존에 작성되어 있는 하나의 추상 메서드만 가지고 있는 Java의 interface 또한 함수형 인터페이스로 취급할 수 있다.
람다 표현식
- 람다 표현식은 함수형 인터페이스를 구현한 클래스 즉, 익명 클래스의 메서드를 단순화 한 표현식이다.
- 함수형 인터페이스의 메서드를 람다 표현식으로 작성해 다른 메서드의 파라미터로 전달할 수 있다.
- 즉, 람다 표현식 전체를 해당 함수형 인터페이스를 구현한 클래스의 인스턴스로 취급한다.
- 람다 표현식 구성
- (String a, String b) -> a.equlas(b)
- 여기서 (String a, String b) => 람다 파라미터 , -> => 화살표 , a.equals(b) => 람다 몸체를 의미한다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
/**
* 하나의 추상 메서드를 가지고 있는 기존 인터페이스를 구현하는 예제
*/
public class LegacyInterfaceExample {
public static void main(String[] args) {
List<Car> cars = Arrays.asList(
new Car(CarMaker.HYUNDAE, CarType.SUV, "팰리세이드", 28000000, true),
new Car(CarMaker.SAMSUNG, CarType.SEDAN, "SM5", 35000000, true),
new Car(CarMaker.CHEVROLET, CarType.SUV, "트래버스", 50000000, true),
new Car(CarMaker.KIA, CarType.SEDAN, "K5", 20000000, false),
new Car(CarMaker.SSANGYOUNG, CarType.SUV, "티볼리", 23000000, true)
);
Collections.sort(cars, new Comparator<Car>() {
@Override
public int compare(Car car1, Car car2) {
return car1.getCarPrice() - car2.getCarPrice();
}
});
for(Car car : cars)
System.out.println("차 이름: " + car.getCarName() + ", 가격: " + car.getCarPrice());
}
}
/*
차 이름: K5, 가격: 20000000
차 이름: 티볼리, 가격: 23000000
차 이름: 팰리세이드, 가격: 28000000
차 이름: SM5, 가격: 35000000
차 이름: 트래버스, 가격: 50000000
*/
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
import com.itvillage.common.Car;
import com.itvillage.common.CarMaker;
import com.itvillage.common.CarType;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
public class LegacyInterfaceFunctionalInterfaceExample {
public static void main(String[] args) {
List<Car> cars = Arrays.asList(
new Car(CarMaker.HYUNDAE, CarType.SUV, "팰리세이드", 28000000, true),
new Car(CarMaker.SAMSUNG, CarType.SEDAN, "SM5", 35000000, true),
new Car(CarMaker.CHEVROLET, CarType.SUV, "트래버스", 50000000, true),
new Car(CarMaker.KIA, CarType.SEDAN, "K5", 20000000, false),
new Car(CarMaker.SSANGYOUNG, CarType.SUV, "티볼리", 23000000, true)
);
Collections.sort(cars, (car1, car2) -> car1.getCarPrice() - car2.getCarPrice());
for (Car car : cars)
System.out.println("차 이름: " + car.getCarName() + ", 가격: " + car.getCarPrice());
}
}
/*
차 이름: K5, 가격: 20000000
차 이름: 티볼리, 가격: 23000000
차 이름: 팰리세이드, 가격: 28000000
차 이름: SM5, 가격: 35000000
차 이름: 트래버스, 가격: 50000000
*/
사용자 정의 Predicate를 익명 클래스로 구현하는 에제
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
public class FunctionalInterfaceExample {
public static void main(String[] args) {
List<Car> cars = Arrays.asList(
new Car(CarMaker.HYUNDAE, CarType.SUV, "팰리세이드", 28000000, true),
new Car(CarMaker.SAMSUNG, CarType.SEDAN, "SM5", 35000000, true),
new Car(CarMaker.CHEVROLET, CarType.SUV, "트래버스", 50000000, true),
new Car(CarMaker.KIA, CarType.SEDAN, "K5", 20000000, false),
new Car(CarMaker.SSANGYOUNG, CarType.SUV, "티볼리", 23000000, true)
);
List<Car> carsFilteredByPrice = CarFilter.filterCarByCustomPredicate(cars, new CarPredicate() {
@Override
public boolean test(Car car) {
return car.getCarPrice() > 30000000;
}
});
for(Car car : carsFilteredByPrice)
System.out.println("차 이름: " + car.getCarName() + ", 가격: " + car.getCarPrice());
List<Car> carsFilteredByCarType = CarFilter.filterCarByCustomPredicate(cars, new CarPredicate() {
@Override
public boolean test(Car car) {
return car.getCarType().equals(CarType.SUV);
}
});
for(Car car : carsFilteredByCarType)
System.out.println("차 이름: " + car.getCarName() + ", 차종: " + car.getCarType());
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
public class FunctionalInterfaceToLamdaExample {
public static void main(String[] args) {
List<Car> cars = Arrays.asList(
new Car(CarMaker.HYUNDAE, CarType.SUV, "팰리세이드", 28000000, true),
new Car(CarMaker.SAMSUNG, CarType.SEDAN, "SM5", 35000000, true),
new Car(CarMaker.CHEVROLET, CarType.SUV, "트래버스", 50000000, true),
new Car(CarMaker.KIA, CarType.SEDAN, "K5", 20000000, false),
new Car(CarMaker.SSANGYOUNG, CarType.SUV, "티볼리", 23000000, true)
);
List<Car> carsFilteredByPrice =
CarFilter.filterCarByCustomPredicate(cars, (Car car) -> car.getCarPrice() > 30000000);
for(Car car : carsFilteredByPrice)
System.out.println("차 이름: " + car.getCarName() + ", 가격: " + car.getCarPrice());
List<Car> carsFilteredByCarType =
CarFilter.filterCarByCustomPredicate(cars, car -> car.getCarType().equals(CarType.SUV));
for(Car car : carsFilteredByCarType)
System.out.println("차 이름: " + car.getCarName() + ", 차종: " + car.getCarType());
}
}
함수 디스크립터 (Function Descriptor)
- 함수형 인터페이스의 추상 메서드를 설명해놓은 시그니처를 함수 디스크립터(Function Descriptor)라고 한다.
- Java8에서는 java.util.function 패키지로 다양한 새로운 함수형 인터페이스를 지원한다.
함수형 인터페이스 | 함수 디스크립터(Function Descriptor) |
---|---|
Predicate | T -> boolean |
Consumer | T -> void |
Function<T,R> | T -> R |
Supplier | ( ) -> T |
BiPredicate<L, R> | (L, R) -> boolean |
BiConsumer<L, R> | (T, U) -> void |
BiFunction<T,U,R> | (T, U) -> R |
Predicate 예시
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
/**
* 함수 디스크립터의 Predicate 예제
*/
public class FunctionalDescriptorPredicateExample {
public static void main(String[] args) {
List<Integer> numbers = Arrays.asList(1, 6, 10, 30, 65, 70, 102);
List<Integer> result = filter(numbers, n -> n > 30);
for(int number : result)
System.out.println(number);
}
private static <T> List<T> filter(List<T> numbers, Predicate<T> p){
List<T> result = new ArrayList<>();
for(T number : numbers)
if(p.test(number))
result.add(number);
return result;
}
}
Comsumer 예제
1
2
3
4
5
6
7
8
9
10
11
public class FunctionalDescriptorConsumer {
public static void main(String[] args) {
List<Integer> numbers = Arrays.asList(1, 6, 10, 30, 65, 70, 102);
forEachPrint(numbers, n -> System.out.println(n));
}
public static <T> void forEachPrint(List<T> numbers, Consumer<T> c) {
for(T number : numbers)
c.accept(number);
}
}
Function 예제
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
/**
* 함수 디스크립터의 Function 예제
*/
public class FunctionalDescriptorFunctionExample {
public static void main(String[] args) {
List<Character> characterList = Arrays.asList('a', 'b', 'c', 'd', 'e');
List<Integer> asciiNumbers = map(characterList, character -> (int) character);
for(int asciiNumber : asciiNumbers)
System.out.println(asciiNumber);
}
public static <T, R> List<R> map(List<T> list, Function<T, R> f){
List<R> result = new ArrayList<>();
for(T t : list)
result.add(f.apply(t));
return result;
}
}
이 글은 inflearn에 있는 Kevin의 알기 쉬운 RxJava 1부를 공부하고 작성한 글입니다.
강의영상 링크