44,000원
다른 수강생들이 자주 물어보는 질문이 궁금하신가요?
- 미해결Kevin의 알기 쉬운 RxJava 1부
Single과 관련해 여쭤보고 싶은 부분이 있습니다!
안녕하세요 선생님! 틈틈이 강의 잘 듣고 있습니다.강의 수강 도중, 궁금한 점이 있어 질문드립니다! Single은 전통적인 client - server 방식의 요청을 처리하는 데 사용한다고 말씀해주셨습니다.실제로 회사에서 single.blocking() 이런 방식으로 처리하는 코드를 본 적이 있는데, single을 해당 의도처럼 사용할 경우, 동기처리 방식에 비해 얻는 이점이 있을까요??제가 아직 생각하기로는 코드는 리액티브이지만 비동기 방식으로 처리하는 것이 아닌 거 같아서요! 또한 강의 영상 3분 정도에서 보여주신 SingleCreateExample 코드에서, 발행자인 Single의 create 메소드의 파라미터인 SingleOnSubscribe<T>가 구현하고 있는 subscribe가 아래 구독자가 구독하는 subscribe() 와 같은 함수가 맞을까요?코드적으로는 둘이 연관이 있어 보여서, SingleObserver<T>와 SingleEmitter<T> 사이의 같은 부모가 있는지 확인 해보았는데 그것두 아니더라구요 ㅠ... 둘이 아예 다른 메소드 인가요??4. 코드를 살펴보다가 RxJavaHooks 라는 유틸성 클래스를 발견하게 되었는데, 함수형 인터페이스들이 막 정의되어 있는 것은 알겠는데 어떻게 해석해야 할 지가 감이 안 잡히더라구요 ㅠㅠ... 혹시 코드를 해석하는데 조언을 주실 수 잇으실까요?..항상 깊게 답변 해주셔서 감사드립니다 :)
- 해결됨Kevin의 알기 쉬운 RxJava 1부
cold/hot publisher 예제 코드와 관련해 질문 드립니다.
안녕하세요! 강의 잘 듣고 있습니다. 본격적인 첫 강의부터 궁금한 점들이 많아 질문 드리게 되었습니다 ㅠ.. 저는 해당 강의를 듣게 된 사유가 웹플럭스 같이 비동기 적으로 처리하는 것에 관심이 많아서 자연스럽게 기본부터 다지고자 해당 강의를 수강하게 되었는데요. 그래서 RxJava 코드가 비동기를 위한 코드라는 인식이 있습니다. 그런데 해당 강의 마지막 부분에 cold/hot publisher 예제 코드에서 콘솔에 데이터가 출려되는 형태를 보면 구독자1이 데이터를 모두 소비하고 구독자2가 그 다음으로 데이터를 소비하는, 동기적으로 처리하는 것처럼 보이더라구요. 혹시 제 생각처럼 동기적으로 처리되고 있는 것이 맞을까요? 그렇다면 사유가 궁금합니다 ㅠRxJava는 사실 단순 pub/sub 형태의 인터페이스를 구현한 구현체에 불과해서 RxJava를 이용해 소스코드를 작성하여도 이걸 비동기적으로 처리하기 위해서는 더 아랫단의 도움을 받아야 하는건지그렇다면 이 코드를 실행하는 was의 영향을 받는건지만약 그냥 java로 실행한다면 비동기적으로 실행할 수 없는 건지아니면 RxJava는 동기적 비동기적으로 소스코드를 작성할 수 있는데, 그냥 현재 예제 코드가 동기적으로 코드를 작성한 것인지아니면 메인 스레드가 구독자1과 2의 역할을 동시에 하고 있기 때문에 순차처리가 되는것인지 또한 비동기에 대한 정의에 대해 여쭤보고 싶습니다.비동기 처리라는 것을 스레드의 동작 방식을 제어하는 것이라고 이해하면 될까요??비동기 처리를 구현하기 위해서는 스레드 제어만 하면 되니까 OS단의 도움을 받지 않고 어플리케이션 단에서 구현을 할 수 있다고 이해해도 괜찮을까요??답변해주시면 감사하겠습니다!
- 미해결Kevin의 알기 쉬운 RxJava 1부
CompletableObserver 클래스의 람다식 표현관련
안녕하세요람다식은 인터페이스안에 구현해야할 메소드가 하나만 있을때 사용 가능한것으로 알고있는데completable.subscribeOn(Schedulers.computation()) .subscribe(new CompletableObserver() { @Override public void onSubscribe(Disposable disposable) { // 아무것도 하지 않음 } @Override public void onComplete() { Logger.log(LogType.ON_COMPLETE); } @Override public void onError(Throwable error) { Logger.log(LogType.ON_ERROR, error); } });여기서 CompletableObserver 는 오버라이드 해야할 메소드가 3개나 있는데 어떤 원리로 completable.subscribeOn(Schedulers.computation()) .subscribe( () -> Logger.log(LogType.ON_COMPLETE), error -> Logger.log(LogType.ON_ERROR, error) );이런식으로 람다표현이 가능한건가요?
- 미해결Kevin의 알기 쉬운 RxJava 1부
1강에 예시로 보여주신 ToDoSample 코드에 관해 질문 드립니다!
안녕하세요! 이제 막 RxJava를 배우기 시작하였습니다 ㅎㅎ1강 14:20초 즈음에 예시로 보여주신 ToDoSample.class코드에 대해 질문 드립니다.java app은 main thread가 종료되어도 다른 non-deamon thread가 실행 중이면 app이 종료되지 않는 것으로 알고 있는데,subscribeOn( Schedulers.io() ) 메소드 실행 시, 다른 thread 가 시작하기도 전에 main thread가 종료되어, 실행 중인 thread가 없어져 app이 종료되었다고 파악해야 할까요??subscribeOn( Schedulers.io() ) 메소드를 실행하였음에도 왜 다른 스레드가 실행이 바로 되지 않는 걸까요??
- 미해결Kevin의 알기 쉬운 RxJava 1부
데이터 결합 연산자 / merge 관련 질문
안녕하세요 강사님!! RxJava 강의 열심히 듣고있습니다. 다름이 아니라 Merge 함수를 실행할 때 Observable을 merge() 결합할 때 interval로 설정한 시간만큼 통지시점에 따라 순차적으로 데이터가 통지된다고 하셨는데제 코드에서는 정상적으로 동작하지 않는 것 같아서 질문 드립니다.1.결과값을 보면 스레드 할당이 제대로 안되는 것 같은데 merge말고 다른 부분에 문제가 있는 건가요?? 결과값도 실행할 때마다 바뀝니다..2. 저는 RxJava3 으로 설정해서 사용 중인데 변경된 부분이 있어서 그럴까요?? 공식문서를 찾아봐도 merge에 관한 변경점은 못찾았습니다ㅠㅠ
- 미해결Kevin의 알기 쉬운 RxJava 1부
DROP 배압 전략에 관한 궁금증
안녕하세요? DROP 배압 전략을 들으면서 이해가 잘 되지 않는 부분이 생겨서 질문드립니다. 이전에 공지해 주신 https://www.inflearn.com/news/527932 도 확인한 상태입니다.위 공지 사항에 내용을 토대로 들어보면, observeOn()의 bufferSize는 발행된 데이터가 담기는 버퍼와는 무관한 스레드를 담는 버퍼로 이해를 하였습니다.그렇다면, DROP 배압 전략이 수행되면 발행된 데이터는 별도의 버퍼에 담기는 것이 아니라 소비자가 데이터를 처리할 때까지 모조리 DROP하는 방식이 맞을까요?만약 이 내용이 맞다면, PPT에 작성해 주신 아래 사진은 버퍼를 제거해야 하지 않을까 싶습니다.
- 미해결Kevin의 알기 쉬운 RxJava 1부
map에서의 TimeUtil.sleep에 관한 궁금점
안녕하세요. 예제 코드를 이것저것 바꿔가며 실행해보다가 궁금한 점이 있어서 질문드립니다.Observable.range(1, 5) .doOnNext(data -> Logger.log(LogType.DO_ON_NEXT, data)) .map(num -> { long time = 1000L; if(num == 4){ time = 1500L; } TimeUtil.sleep(time); return num; }) .timeout(1200L, TimeUnit.MILLISECONDS) .subscribe( data -> Logger.log(LogType.ON_NEXT, data), error -> Logger.log(LogType.ON_ERROR, error) ); doOnNext() | main | 22:42:06.634 | 1 onNext() | main | 22:42:07.636 | 1 doOnNext() | main | 22:42:07.636 | 2 onNext() | main | 22:42:08.636 | 2 doOnNext() | main | 22:42:08.636 | 3 onNext() | main | 22:42:09.637 | 3 doOnNext() | main | 22:42:09.637 | 4 onERROR() | RxComputationThreadPool-1 | 22:42:10.837 | java.util.concurrent.TimeoutException: The source did not signal an event for 1200 milliseconds and has been terminated.위와 같이 코드를 작성하였을때 원본 데이터가 delay함수의 유형2번과 유사하게 동작해서 LogType doOnNext와 doNext가 번갈아 가면서 출력되었습니다.range()에서 생성된 데이터가 map으로 들어가기 까지는 delay가 없어서 doOnNext가 4번 찍히고 delay 이후에 onNext가 4번찍힐 것으로 예상했는데 번갈아가면서 찍히는 이유가 무엇인가요??
- 미해결Kevin의 알기 쉬운 RxJava 1부
강의 내용을 정리해서 개인 블로그에 올려도 될까요?
강사님 안녕하세요. 최근 회사에서 reactive streams를 사용하게 되어 아주 유용하게 강의 듣고 있습니다. 요번 강의부터 느껴지는 점이 개념이 조금 어려워진다고 생각해서, 꼼꼼하게 내용을 정리하고자 개인 기술 블로그에 강의 내용들을 정리해서 출처와 함께 업로드하고자 하는데, 그렇게 해도 되는지 질문 남깁니다.
- 해결됨Kevin의 알기 쉬운 RxJava 1부
TimeUtil.sleep 관련 질문
리액티브 연산자 개요 및 생성 연산자 강의에서 질문 있습니다. TimeUtil.sleep 과 관련된 질문입니다. 이와 관련된 질문이 이미 있었고, 해당 답변도 봤는데요. (Q&A 링크 : https://inf.run/TUZc ) 뭔가 제가 알던 쓰레드 동작 방식과 차이가 있어서 재질문합니다. 이미 답변 주신 글에서는 "이유는 interval 연산자는 내부적으로 main 쓰레드가 아닌 Computation 쓰레드에서 실행이 되기 때문에 Observable.interval.. 코드가 실행이 되기도 전에 main 쓰레드가 종료되기 때문입니다." 라고 답변을 주셨는데요. 그런데 제가 알기로는 main 쓰레드와 별개로 동작하는 쓰레드가 있으면 애플리케이션이 종료되지 않는 걸로 알고 있습니다. 예를 들어서 아래와 같은 간단한 코드를 실행하면 바로 알 수 있습니다. public static void main(String[] args) { System.out.println("main Start!"); Thread thread = new Thread(() -> { try { Thread.sleep(3000); System.out.println("wow"); } catch (InterruptedException e) { throw new RuntimeException(e); } }); thread.start(); System.out.println("main end"); } 실행해보면 main 쓰레드와 관련된 동작은 모두 끝나도 3초가 지나야만 프로세스가 종료됩니다. 혹시 답변에서 주셨던 Computation 쓰레드는 혹시 Daemon 쓰레드인가요? 아니면 제가 놓치는 부분이 있는 건가요??
- 미해결Kevin의 알기 쉬운 RxJava 1부
배압 전략 중에서 DROP 전략과 관련해서 질문 있습니다.
안녕하세요, 강의 진짜 재밌게 보고 있는 수강생입니다 ^^. Observable과 Flowable에 대한 이해 강의를 보다 조금 애매한 부분이 생겨서 질문드릴게 있습니다. 질문1. 제가 처음에 인지했던 DROP전략은 27:54 에 나오는 대로 "버퍼가 비워지는 시점에 Drop 되지 않은 데이터"가 버퍼에 담긴다는 걸로 인식 했습니다. 그런데 강의 32:56 쯤에 "소비자 쪽에서 데이터의 처리가 끝나지 않으면 생산자 쪽에서 통지한 데이터는 DROP이 된다"라고 알려주십니다. 처음에는 "버퍼가 비워지기 전까지"가 DROP의 조건이였는데, 그 이후에 들은 건 "소비자가 데이터 처리를 계속 하고 있는 상태일 때"가 DROP 조건으로 바뀌는 거 같은데... 정확히 어떤게 맞는 건가요? 질문2. 29:04 의 배압전략(DROP 전략) 그림에서는 버퍼의 크기가 그림으로 보였는데, 그 이후 코드를 보여주실 때(29:14)는 그런 버퍼의 크기를 지정하는 부분이 보이지 않습니다. 버퍼의 크기가 어떻게 지정된 건가요? 그리고 현재 코드 상에서는 버퍼의 크기가 어떻게 되나요?
- 미해결Kevin의 알기 쉬운 RxJava 1부
Error 발생 시에도 계속 처리 방법
안녕하세요. 강의 잘 수강중인 수강생입니다. 받아온 리스트를 flatMap을 통해 각각 observable 작업을 만들고 순차적으로 실행할 때 중간에 하나가 실패하더라도 계속 그 다음 Observable로 넘어가도록 하는 방법은 없나요? 아니면 혹시 좋은 처리 방법이 있을지요. try-catch를 flatMap 내부 블럭에서 쓰기엔 rxJava스럽지 않은 방법이고... onErrorReturnNext같은 함수를 쓰기도 좀 애매하네요. 가운데 fetchData() 부분만 봐주시면 될 것 같습니다 import io.reactivex.Completable import io.reactivex.Observable import io.reactivex.Single import org.mockito.ArgumentMatchers.anyInt import org.mockito.Mockito import org.mockito.kotlin.eq import org.mockito.kotlin.given import org.mockito.kotlin.whenever import java.lang.Exception val db = mutableListOf<String>() fun <T : Any> safeEq(value: T): T = eq(value) ?: value fun main() { val fakeSentenceMaker: SentenceMaker = Mockito.mock(SentenceMaker::class.java) whenever(fakeSentenceMaker.getNonLuckySentence(anyInt())) .thenCallRealMethod() whenever(fakeSentenceMaker.getLuckySentence()) .thenCallRealMethod() given(fakeSentenceMaker.getNonLuckySentence(safeEq(4))) .willAnswer{ throw Exception("실패!") } val repository = Repository(fakeSentenceMaker) repository.fetchData() .subscribe({ println("성공 >> ") }, { println("실패 >> $it") }) Thread.sleep(1000) db.also { println(it) } } class Repository( private val sentenceMaker: SentenceMaker ) { private fun getList(): Single<List<Int>> { return Single.just(listOf(1, 2, 3, 4, 5, 6, 7, 8)) } fun fetchData(): Completable { return getList() .flatMapObservable { Observable.fromIterable(it) } .flatMap { println("현재 데이터 >> $it") if (it == 7) { sentenceMaker.getLuckySentence() } else { sentenceMaker.getNonLuckySentence(it) } } // .onErrorResumeNext(Observable.just("Error!")) .flatMapCompletable { println("before emit >> $it") saveData(it) } } fun saveData(data: String): Completable { return Completable.create { emitter -> println("emit >> $data") db.add(data) emitter.onComplete() } } } class SentenceMaker { fun getLuckySentence(): Observable<String> { val luckySentence = "7은 행운의 숫자입니다" return Observable.just(luckySentence) } fun getNonLuckySentence(num: Int): Observable<String> { val nonLuckySentence = "${num}은 행운의 숫자가 아닙니다" return Observable.just(nonLuckySentence) } }
- 미해결Kevin의 알기 쉬운 RxJava 1부
선언형 프로그래밍과 명령형 프로그래밍
안녕하세요 강사님~! 예제로 들어주신 선언형 프로그래밍 소스코드도 number가 6 이상, 2로 나눌 수 없는 것을 filtering 한다는 점에서 앞의 명령형처럼 구체적 알고리즘이 적혀있는 것 같아서 두 차이점이 헷갈리는데, 좀 더 명확히 구분할 수 있는 방법 없을까요? for문 역할 대신 stream, filter로만 바뀐걸로 보여서요 ㅠ 함수형 프로그래밍이, 명령형 프로그래밍, 선언형 프로그래밍이 헷갈립니다.
- 미해결Kevin의 알기 쉬운 RxJava 1부
첫번째 강의 부터 이번강의까지 수강하면서 궁금한점 질문드립니다.
- 학습 관련 질문을 남겨주세요. 상세히 작성하면 더 좋아요! - 먼저 유사한 질문이 있었는지 검색해보세요. - 서로 예의를 지키며 존중하는 문화를 만들어가요. - 잠깐! 인프런 서비스 운영 관련 문의는 1:1 문의하기를 이용해주세요. 안녕하세요. 강사님 Spring Webflux가 앞으로 대세로 많이 사용될 것 같은 생각이 들어서 RxJava를 수강하면서 강의를 잘 듣고 있습니다. 현재까지 강의 들으면서 궁금한점이 있어서 질문드리는데요, 첫번째 강의에서 사용한 코드는 main() 메서드 마지막에 Thread.sleep()이 없으면 별도의 쓰레드에 의해 코드가 실행되면서 결과값을 볼 수가 없었는데 지금은 main()메서드 마지막에 Thread.sleep()을 안주어도 되는 것 별도의 쓰레드풀을 코드에서 사용하지 않고 메인쓰레드에서 결과값이 나오는 걸 확인할 수 있었습니다. 그렇다고 하면 RxJava 프로그래밍도 subscribeOn이나 observeOn에 쓰레드풀 지정여부에 따라서 동기, 비동기로 실행되는 것인지요?
- 해결됨Kevin의 알기 쉬운 RxJava 1부
안녕하세요. 질문이 있습니다.
이전 강의때도 궁금했던 거였는데 메인함수 마지막에 Thread.sleep()은 어떤 이유에서 필요한 건지 궁금합니다. 알려주실 수 있을까요...? 감사합니다.
- 미해결Kevin의 알기 쉬운 RxJava 1부
logger 가 없는데 util 폴더도 같이 갖다놔야 하나요?
이해하기 쉬운 강의 감사합니다. 근데, 코드 작성해보면서 따라가고 있는데, Logger부분이 구현이 안되고 이걸 따라가보니 import com.itvillage.utils.Logger; 이걸 갖다 쓰고 있고 https://github.com/ITVillage-Kevin/rxjava/blob/master/src/main/java/com/itvillage/utils/Logger.java Util 을 선언해서 갖다 쓰시는게 있네요.....ㅠㅠ 이거 혹시 안내해 주셨나요? 왜 기억에 없지...... 혹시 없다면 가이드가 필요 할 것 같습니다
- 미해결Kevin의 알기 쉬운 RxJava 1부
amb 연산자
예제에서 amb 연산자에 입력값 observable 중에서 두번째, 세번째 observable은 메시지 발행 자체를 안하는걸까요? amb 연산자 다이어그램과 예제를 보고 출력결과를 예상했을 때, 두번째, 세번째 observable의 데이터가 amb() 소비자에게 전달만 안될 뿐이지, 데이터를 발행하고 종료가 되면 doOnComplete()에 있는 로그가 찍히지 않을까 생각했었거든요. # branch A's sales # 완료 # branch B's sales # branch C's sales 이런식으로 로그가 찍힐거라고 예상했었어요. 제가 어떤 부분을 잘못 생각하고 있는걸까요?
- 미해결Kevin의 알기 쉬운 RxJava 1부
질문 드립니다.
아직 강의 초기라 잘 이해되지 않는 부분이 있습니다. drop 된다는 의미 버려진다는 것이 데이터를 subsciber에서 모두 처리 못한다는 의미인가요? 그렇다면 유실된 데이터 처리는 어떻게 되는건가요? drop된 데이터를 다시 소비하는 걸로 생각했는데 아닌가요? 감사합니다.
- 해결됨Kevin의 알기 쉬운 RxJava 1부
concatEager( ) 연산자에 관하여
안녕하세요, 해당 강의에서 materialize / dematerialize 파트에서 언급된 concatEager( ) 연산자에 알아보면서 어떻게 사용해야하는 것인지 정확히 알고 싶습니다. - Observable.java (concat 연산자) @CheckReturnValue@NonNull@SchedulerSupport(SchedulerSupport.NONE)public static <T> Observable<T> concat(ObservableSource<? extends T> source1, ObservableSource<? extends T> source2) { ObjectHelper.requireNonNull(source1, "source1 is null"); ObjectHelper.requireNonNull(source2, "source2 is null"); return concatArray(source1, source2);} - Observable.java (concatEager 연산자) @CheckReturnValue@SchedulerSupport(SchedulerSupport.NONE)public static <T> Observable<T> concatEager(ObservableSource<? extends ObservableSource<? extends T>> sources) { return concatEager(sources, bufferSize(), bufferSize());} 위 API 소스를 보다시피 concatEager의 파라미터는 'ObservableSource<? extends ObservableSource<? extends T>>' 타입을 넣어야 한다고 명시가 되어있는데요, 저 모양이 예제 'ObservableMaterialExample02.java'처럼 Observable.just( ... )의 파라미터에 Observable 넣어야하는 형태인건가요? 저런 타입이 어떠한 모양인지 감이 안잡혀서 여쭤봅니다.
- 해결됨Kevin의 알기 쉬운 RxJava 1부
Reactive Streams의 구성요소들과 RxJava의 구성요소들의 관계?
안녕하세요, 강의를 복습하면서 의문점이 생겨 질문드립니다 RxJava는 Reactive Streams의 인터페이스들을 구현한 구현체라고 소개가 되어있는데요, Reactive Streams에서 제공하는 인터페이스 Publisher, Subscriber / RxJava에서 구성요소는 Observable, Observer(구독자) 등이 있는데 (Publisher - Observable) 관계와 (Subscriber - Observer)관계로 이어 서로 비교를 해볼 수 있지 않을까라는 생각이 들었습니다. RxJava가 Reactive Streams의 인터페이스들을 구현했다고 했으니,Observable의 코드만 살펴봐도 Publisher를 상속한 부분이 있는지 (당연히) 확인할 수는 없었고, 제가 찾아본 (Publisher - Observable) 간 차이점은 패키지 구분이라는 것만 확인할 수 있었습니다. import io.reactivex.Observable;import org.reactivestreams.Publisher; 서론이 길었는데요, RxJava와 Reactive Streams의 각각의 구성요소들 간 관계를 '기존 인터페이스의 구현체의 일부일 뿐이다'라고 간단하게 이해하고 넘어가면 되는 걸까요?
- 해결됨Kevin의 알기 쉬운 RxJava 1부
ObservableSequenceEqualExample.java 예제의 delay( ) 연산자 질문있습니다
안녕하세요, 해당 예제에서의 delay( ) 연산자를 첫 번째 유형(delay(Long delay, TimeUnit unit))으로 바꿔보았는데, 콘솔에 수행 결과 출력없이 종료됩니다. public class ObservableSequenceEqualExample { public static void main(String[] args) { Observable<CarMaker> observable1 = Observable.fromArray(SampleData.carMakers) .subscribeOn(Schedulers.computation()) .delay(300L, TimeUnit.MILLISECONDS) .doOnNext(data -> Logger.log(LogType.DO_ON_NEXT, "# observable1 : " + data)); Observable<CarMaker> observable2 = Observable.fromArray(SampleData.carMakers) .delay(100L, TimeUnit.MILLISECONDS) .doOnNext(data -> Logger.log(LogType.DO_ON_NEXT, "# observable2 : " + data)); Observable.sequenceEqual(observable1, observable2) .subscribe(data -> Logger.log(LogType.ON_NEXT, data)); }} Schedules.computation을 설정해서 그런가 싶어 주석 처리해보아도 결과는 동일했습니다. 어째서 두 유형의 delay( )이 결과 값이 다른지 모르겠습니다 * 추가 내용 (자문자답 아님!) 왜 이러한 차이점이 있는지 확인해본 바로는첫 번째 유형의 delay는 아래와 같이 스케줄러를 통해 computation 스레드로 지정하는 것을 확인했습니다. 이 때문에 observable1, observable2가 각 스레드 computation로 실행되기 때문에 Thread.sleep( )을 주지 않는 이상 콘솔에 출력이 안되는 것 같습니다. - Observable.java @CheckReturnValue@SchedulerSupport(SchedulerSupport.COMPUTATION)public final Observable<T> delay(long delay, TimeUnit unit) { return delay(delay, unit, Schedulers.computation(), false);} 반면 두 번째 유형의 delay 코드는 첫 번째 유형과 달리 실행할 스레드를 지정하는 코드가 없고 flatMap을 통해 데이터를 1개 씩 리턴하기 때문에 sequenceEqual( ) 연산자가 각각의 데이터를 비교할 수 있는 것이 아닐까 추측해봅니다... @CheckReturnValue@SchedulerSupport(SchedulerSupport.NONE)public final <U> Observable<T> delay(final Function<? super T, ? extends ObservableSource<U>> itemDelay) { ObjectHelper.requireNonNull(itemDelay, "itemDelay is null"); return flatMap(ObservableInternalHelper.itemDelay(itemDelay));} 혹시 제가 추측한 내용 중에 틀린 부분이 있는지 확인부탁드립니다ㅜ