Posts RxJava - 함수형 인터페이스와 람다
Post
Cancel

RxJava - 함수형 인터페이스와 람다

함수형 인터페이스란?

  • 함수형 인터페이스는 말 그대로 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)
PredicateT -> boolean
ConsumerT -> 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부를 공부하고 작성한 글입니다.
강의영상 링크

This post is licensed under CC BY 4.0 by the author.

RxJava - Single vs Maybe vs Completable

RxJava - 함수형 메서드 레퍼런스

Comments powered by Disqus.