티스토리 뷰

프로그래밍언어/Java

RxJava 시작

데니 Denny 2019. 4. 20. 17:02
반응형
SMALL

RxJava란

RxJava란 Reactive Programming을 하기위한 라이브러리인 Rx(Reactive Extensions)의 JVM판입니다.

StreamAPI + 비동기 콜백같은 느낌.

이벤트를 정의한 Observable 인스턴스에 대해 짧은 함수를 엮은(체인) 스트림같이 이벤트 결과 데이터를 가공하는 처리를 정의, 지연실행, 비동기 콜백을 할 수있다.

기본적인 사용법

처리를 싱행하고 결과를 전달하는 Observable, 결과를 수신할때의 처리를 정하는 Observer를 사용한다.

우선 “Hello”와 “world”라는 2개의 문자열을 결과로 전달하는 심플한 Observable를 생성해보자.

※java.util.Observable가 아니므로 주의

Observable<String> myObservable = Observable.create( 
	new Observable.OnSubscribe<String>() { 
    	@Override public void call(Subscriber<? super String> subscriber) { 
        	subscriber.onNext("Hello"); 
            subscriber.onNext("world!"); 
            subscriber.onCompleted(); 
        } 
    } 
);

 

다음으로 결과를 수신받는 측인 Observer 생성.

Observer<String> myObserver = new Observer<String>() {
    @Override public void onCompleted() {
    
    } 
    @Override public void onError(Throwable e) { 
    
    } 
    @Override public void onNext(String s) { 
    	System.out.println(s); 
    } 
};

 

마지막으로 Observable의 subscribe 메소드에 Observer 전달하여 실행.

이 시점에 처음으로 Observable가 실행되고, onNext에 전달한 결과가 순차적으로 Observer에 전달한다.

myObservable.subscribe(myObserver);

그리고,

“Hello”

“world”

가 출력된다.

좀 더 간결하게 작성

위는 친절한 예시이지만, 정의되어 있는 여러가지 메소드를 활용하는 것으로 좀 더 간결하게 기술할 수 있다. from은 수신받은 배열이나 Iterator의 요소를 순차적으로 결과로 반환하는 Observable를 생성해준다.

그리고, subscribe에는 Observer 대신으로 함수(Action1 인터페이스 인스턴스)를 1개만 전달하는 것으로 onNext시에 함수를 실행해준다.

Observable<String> myObservable = Observable.from(new String[]{"Hello", "world!"}); 
	myObservable.subscribe(new Action1<String>() {
		@Override public void call(String s) {
        	System.out.println(s);
        }
    }
);

 

Java8일아면 Action1은 함수형 인터페이스가 되므로 여기의 처리는 람다식으로 1줄이 된다.

Observable.from(new String[]{"Hello", "world!"}).subscribe(System.out::println);

Observable를 새로운 Observable으로 변환

map

map 메소드는 Observable를 별도의 Observable로 변환한다.

예를들면 조금전 Observable로부터 받을려는 것이 문자열 그대로가 아니라 문자열의 길이라고하자. map을 사용하면 문자열을 전달하는 Observable을 기반으로 문자열의 길이를 전달하는 새로운 Observable를 간단하게 생성할수 있다.

Observable.from(new String[]{"Hello", "world!"})
    .map(new Func1<String, Integer>() {
        @Override public Integer call(String s) {
            return s.length();
        }
    })
    .subscribe(new Action1<Integer>() {
        @Override public void call(Integer i) {
            System.out.println(i)
        }
    }
);

 

이것은,

“5”

“6”

을 출력한다.

flatMap

그럼 배열의 요소가 Nest한 경우는 어떨까?

flatMap을 사용해 Nest한 요소를 병렬 결과로서 전달할수 있다.

여기서 flatMap의 Func1에서는 Observable반환하지만, flatMap은 이 Observable를 분해해 늘여놓은 1개의 Observable를 생성해준다.

// jekyll 문제로 다음라인은 변환이 필요합니다
// < --> {
// > --> }
String[][] helloAndGoodbye = <<"Hello", "world!">, <"goodbye", "world!">>;
Observable.from(helloAndGoodbye)
        .flatMap(new Func1<String[], Observable<String>>() {
            @Override
            public Observable<String> call(String[] strings) {
                // 이곳에 전달되는 것은 2개의 배열. 그것을 Observable해서 반환
                return Observable.from(strings);
            }
        })
        .map(new Func1<String, Integer>() {
            @Override
            public Integer call(String s) {
                // 여기에 전달되는 것은 4개의 문자열
                return s.length();
            }
        })
        .subscribe(new Action1<Integer>() {
            @Override
            public void call(Integer i) {
                 System.out.println(i)
            }
        });

 

“5”

“6”

“7”

“6”

이 출력된다.

marge

복수 Observable를 합성하는 marge를 사용해 flatMap을 사용하지않고 적는것이 가능하다.

// jekyll 문제로 다음라인은 변환이 필요합니다
// < --> {
// > --> }
String[][] helloAndGoodbye = <<"Hello", "world!">, <"goodbye", "world!">>;
Observable.merge(Observable.from(helloAndGoodbye[0]), Observable.from(helloAndGoodbye[1]))
        .map(new Func1<String, Integer>() {
            @Override
            public Integer call(String s) {
                return s.length();
            }
        })
        .subscribe(new Action1<Integer>() {
            @Override
            public void call(Integer i) {
                 System.out.println(i)
            }
        });

filter

filter를 사용하면 결과를 취사선택하는 것이 가능하다.

여기에서는 문자열이 “world!”와 일차하는것을 배제한다.

// jekyll 문제로 다음라인은 변환이 필요합니다
// < --> {
// > --> }
String[][] helloAndGoodbye = <<"Hello", "world!">, <"goodbye", "world!">>;
Observable.from(helloAndGoodbye)
        .flatMap(new Func1<String[], Observable<String>>() {
            @Override
            public Observable<String> call(String[] strings) {
                return Observable.from(strings);
            }
        })
        .filter(new Func1<String, Boolean>() {
            @Override
            public Boolean call(String s) {
                return !s.equals("world!");
            }
        })
        .map(new Func1<String, Integer>() {
            @Override
            public Integer call(String s) {
                return s.length();
            }
        })
        .subscribe(new Action1<Integer>() {
            @Override
            public void call(Integer i) {
                 System.out.println(i)
            }
        });

“5”

“7”

이 출력된다.

여기까지를 Java8의 람다식으로 적으면 아래처럼 된다.

// jekyll 문제로 다음라인은 변환이 필요합니다
// < --> {
// > --> }
String[][] helloAndGoodbye = <<"Hello", "world!">, <"goodbye", "world!">>;
Observable.from(helloAndGoodbye)
        .flatMap(Observable::from)
        .filter(s -> !s.equals("world!"))
        .map(String::length)
        .subscribe(System.out::println);

이름이 없는 클래스가 줄지어 있으면 솔직히 그다지 보기쉬운 코드가 아니지만, 람다식으로 하면 if나 for를 많이사용하는 처리를 기술하는 것과 비교해 꽤 직관적인 코드가 된다.

 

출처 : http://pluu.github.io/blog/rx/2015/04/29/rxjava/

반응형
LIST

'프로그래밍언어 > Java' 카테고리의 다른 글

스레드 우선순위  (0) 2019.06.17
정적 바인딩 vs. 동적 바인딩  (0) 2019.06.13
JAVA 직렬화와 Transient Keyword  (0) 2019.06.13
반응형
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/05   »
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
글 보관함