Java_리액티브 프로그래밍

Minki CHO·2023년 1월 29일
0

CodeStates

목록 보기
31/43

Hello, Reactive로 알아보는 리액티브 프로그래밍 구조

리액티브 프로그래밍의 대표적인 특징 : 선언형 프로그래밍 방식을 사용

명령형 프로그래밍

public class ImperativeProgrammingExample {
    public static void main(String[] args){
        // List에 있는 숫자들 중에서 4보다 큰 짝수의 합계 구하기
        List<Integer> numbers = List.of(1, 3, 6, 7, 8, 11);
        int sum = 0;

        for(int number : numbers){
            if(number > 4 && (number % 2 == 0)){
                sum += number;
            }
        }

        System.out.println(sum);
    }
}

:List에 포함된 숫자들을 for문을 이용해 순차적으로 접근한 후
if 문으로 특정 조건에 맞는 숫자들만 sum 변수에 더해서 합계를 구함

? 명령형 프로그래밍이란?
:코드가 어떤 식으로 실행되어야 하는지 구체적인 로직들이 코드 안에 그대로 들어남

선언형 프로그래밍

public class DeclarativeProgramingExample {
    public static void main(String[] args){
        // List에 있는 숫자들 중에서 4보다 큰 짝수의 합계 구하기
        List<Integer> numbers = List.of(1, 3, 6, 7, 8, 11);

        int sum =
                numbers.stream()
                        .filter(number -> number > 4 && (number % 2 == 0))
                        .mapToInt(number -> number)
                        .sum();

        System.out.println("# 선언형 프로그래밍: " + sum);
    }
}

:Java Stream API 사용하기 때문에
코드 상에 보이지 않는 내부 반복자가 명령형 프로그래밍 방식에서 사용하는 for문을 대체함
:filter() 메서드(Operation)가 if문을 대신해서 조건에 만족하는 숫자를 필터링

? Stream API를 사용하는 것이 왜 선언형 프로그래밍 방식일까?
:명령형 프로그래밍 방식으로 작성된 코드는 위에서 아래로 순차적으로 실행됨
:but.
Stream API를 사용한 코드는 numbers.stream().filter().mapToInt().sum() 같은 메서드 체인이 순차적으로 실행되지 않음
:filter()나 mapToInt() 메서드에 파라미터를 전달하기 때문에
즉시 호출되는 것처럼 생각될 수 있으나 그렇지 않음
:Stream의 경우 최종 연산을 수행하는 메서드를 호출하지 않으면 앞에서 작성한 메서드 체인이 실행되지 않음
:즉, Stream의 메서드 체인(중간 연산)에는 이러이러한 작업을 해달라고 선언(요청)하는 람다 표현식만 넘겨주고, 최종 연산이 호출될 때, 비로소 전달받은 람다 표현식을 기반으로 동작 수행함

리액티브 프로그래밍의 구조 예시

import reactor.core.publisher.Mono;

// 리액티브 프로그래밍 기본 구조
public class HelloReactiveExample01 {
    public static void main(String[] args) {
        // (1) Publisher의 역할
        Mono<String> mono = Mono.just("Hello, Reactive");

        // (2) Subscriber의 역할
        mono.subscribe(message -> System.out.println(message));
    }
}

:Publisher :데이터를 emit하는 역할
:Subscriber :Publisher가 emit한 데이터를 전달받아서 소비하는 역할

위 코드에서
Publisher의 역할을 하는 것 = Mono
Subscriber의 역할을 하는 것 = subscribe() 메서드 내부에 정의된 람다 표현식인 message -> System.out.println(message)임

리액티브 프로그래밍도 아래처럼 메서드 체인을 구성할 수 있음

import reactor.core.publisher.Mono;

// 리액티브 프로그래밍 기본 구조
public class HelloReactiveExample02 {
    public static void main(String[] args) {
        Mono
            .just("Hello, Reactive")
            .subscribe(message -> System.out.println(message));
    }
}

리액티브 프로그래밍에서 사용되는 용어 정의

import reactor.core.publisher.Flux;

import java.util.List;

public class ReactiveGlossaryExample {
    public static void main(String[] args) {
        Flux
            .fromIterable(List.of(1, 3, 6, 7, 8, 11))
            .filter(number -> number > 4 && (number % 2 == 0))
            .reduce((n1, n2) -> n1 + n2)
            .subscribe(System.out::println);

    }
}

1 Publisher
:데이터를 내보내는 주체
:위 코드에서 Flux = Publisher

2 Emit
:Publisher가 데이터를 내보내는 것

3 Subscriber
:Publisher가 emit한 데이터를 전달받아서 소비하는 주체를 의미
:위 코드에서 System.out::println = Subscriber

4 Subscribe
:구독
:위 코드에서 subscribe() 메서드 호출 = 구독

5 Signal
:Publisher가 발생시키는 이벤트
:위 코드에서 subscribe() 메서드 호출되면
Publisher인 Flux는 숫자 데이터를 하나씩 하나씩 emit 함
:이때 숫자 데이터를 하나씩 emit 하는 것 = 리액티브 프로그래밍에서는 이벤트가 발생하는 것으로 간주
:이 이벤트 발생을 다른 컴포넌트에게 전달하는 것 = Signal을 전송한다

6 Operator
:리액티브 프로그래밍에서 어떤 독작을 수행하는 메서드를 의미
:위 코드에서 fromIterable(), filter(), reduce() 등 메서드 하나하나를 Operator라고 함

7 Sequence
:Operator 체인으로 표현되는 데이터의 흐름을 의미
:위 코드에서 Operator 체인으로 작성된 코드 자체를 하나의 Sequence라고 이해하면 됨

8 Upstream/Downstream
:Sequence 상의 특정 Operator를 기준으로
위쪽 Sequence 일부를 Upstream이라고 하고
아래쪽 Sequence 일부를 Downstream이라고 함
:위 코드에서 filter() Operator 기준으로 보면
filter() Operator 위쪽의 fromIterable() Operator은 Upstream
filter() Operator 아래쪽의 reduce() Operator은 Downstream

profile
Developer

0개의 댓글