寻找更好的方法来组合RxJava可观察对象
我正在开发一个从多个来源收集数据并按顺序应用一些转换的工具。我目前正在将此功能从Java8流转换为使用ReactiveX/RxJava 下面,您可以看到演示当前RxJava实现的单元测试 虽然它有效,但我对结果还不够满意,我正在寻找如何改进它的指导寻找更好的方法来组合RxJava可观察对象,java,observable,reactive-programming,rx-java2,reactivex,Java,Observable,Reactive Programming,Rx Java2,Reactivex,我正在开发一个从多个来源收集数据并按顺序应用一些转换的工具。我目前正在将此功能从Java8流转换为使用ReactiveX/RxJava 下面,您可以看到演示当前RxJava实现的单元测试 虽然它有效,但我对结果还不够满意,我正在寻找如何改进它的指导 我的两个问题是: 1。每个源返回一个结果列表(列表)。因为转换需要在完整的数据集上执行,所以我需要将多个列表合并为一个列表。 现在代码如下所示: Observable<List<List<String>>> st
我的两个问题是: 1。每个源返回一个结果列表(列表)。因为转换需要在完整的数据集上执行,所以我需要将多个列表合并为一个列表。 现在代码如下所示:
Observable<List<List<String>>> stage = Observable.merge(src1, src2, src3, src4);
final List<List<String>> collector = new ArrayList<>();
Single<List<List<String>>> combinedData = stage.reduce(collector, (list, items) -> {
list.addAll(items);
return list;
});
基本上,我需要一种方法将Observable applyAsync(List input)
应用到输入List
上,并在每次转换(Observable
)上递归地继续这样做
它类似于可观察的。reduce
,但累加器函数需要在每次迭代中更改
下面是我编写的完整单元测试代码:
import io.reactivex.Observable;
import io.reactivex.schedulers.Schedulers;
import org.mockito.ArgumentCaptor;
import org.testng.annotations.Test;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.contains;
import static org.hamcrest.Matchers.*;
import static org.mockito.Mockito.*;
public class ObservableTest {
@Test
public void testObservable() throws Exception {
// ARRANGE
final CountDownLatch DONE = new CountDownLatch(1);
// init source objects
Observable<List<List<String>>> src1 = Observable.just(makeMatrix(Arrays.asList("src11")));
Observable<List<List<String>>> src2 = Observable.just(makeMatrix(Arrays.asList("src21", "src22")));
Observable<List<List<String>>> src3 = Observable.just(makeMatrix(Arrays.asList("src31", "src32", "src33")));
Observable<List<List<String>>> src4 = Observable.just(makeMatrix(Arrays.asList("src41"), Arrays.asList("src51")));
// prepare transformations and processor
List<Transform> transforms = Arrays.asList(new Transform(1, 100), new Transform(2, 0));
Processor processor = spy(new Processor());
// ACT
// Concat sources
Observable<List<List<String>>> stage = Observable.merge(src1, src2, src3, src4);
// Merge individual into matrix
// (#1) Can the reduce operation be written without the accumulator?
final List<List<String>> collector = new ArrayList<>();
Single<List<List<String>>> combinedData = stage.reduce(collector, (list, items) -> {
list.addAll(items);
return list;
});
// Transform
stage = combinedData.toObservable();
for (Transform t : transforms) {
// (#2) Can a series of transforms be applied sequentially to a Single (List<List<String>>), without the use of a for-loop?
stage = stage.flatMap(t::applyAsync);
}
// Process
stage.doOnComplete(DONE::countDown)
.subscribeOn(Schedulers.computation())
.subscribe(o -> System.out.println(processor.printList(o)));
// wait for processing to complete
DONE.await();
// ASSERT
// The sources should be combined in a single matrix
@SuppressWarnings("unchecked")
ArgumentCaptor<List<List<String>>> resultCaptor = ArgumentCaptor.forClass(List.class);
verify(processor, times(1)).printList(resultCaptor.capture());
List<List<String>> resultMatrix = resultCaptor.getValue();
// result matrix should not be null and all transformations should be applied in order (T1, T2, etc.)
assertThat(resultMatrix, notNullValue());
assertThat(resultMatrix.stream().flatMap(Collection::stream).collect(Collectors.toList()), everyItem(containsString("T1-T2")));
assertThat(resultMatrix, not(hasItem(hasItem(containsString("T2-T1")))));
}
private List<List<String>> makeMatrix(List<String> items) {
return Collections.singletonList(items);
}
private List<List<String>> makeMatrix(List<String> items, List<String> moreItems) {
return Arrays.asList(items, moreItems);
}
static class Processor {
String printList(List<List<String>> input) {
return input.stream().map(rows -> rows.stream().collect(Collectors.joining(" | ")))
.collect(Collectors.joining(System.lineSeparator()));
}
}
static class Transform {
final int n;
private final int delay;
Transform(int n, int delay) {
this.n = n;
this.delay = delay;
}
private Observable<List<List<String>>> applyAsync(List<List<String>> input) {
return Observable.just(input).map(this::apply).delay(delay, TimeUnit.MILLISECONDS);
}
private List<List<String>> apply(List<List<String>> input) {
return input.stream()
.map(row -> row.stream()
.map(this::transform)
.collect(Collectors.toList())
)
.collect(Collectors.toList());
}
private String transform(String input) {
return input + "-T" + n;
}
}
}
import io.reactivex.Observable;
导入io.reactivex.schedulers.schedulers;
导入org.mockito.ArgumentCaptor;
导入org.testng.annotations.Test;
导入java.util.ArrayList;
导入java.util.array;
导入java.util.Collections;
导入java.util.List;
导入java.util.concurrent.CountDownLatch;
导入java.util.concurrent.TimeUnit;
导入java.util.stream.collector;
导入静态org.hamcrest.matcherasert.assertThat;
导入静态org.hamcrest.Matchers.contains;
导入静态org.hamcrest.Matchers.*;
导入静态org.mockito.mockito.*;
公共类可观测测试{
@试验
public void testObservable()引发异常{
//安排
最终倒计时锁存器完成=新倒计时锁存器(1);
//初始化源对象
可观测的src1=可观测的.just(makeMatrix(Arrays.asList(“src11”));
Observable src2=Observable.just(makeMatrix(Arrays.asList(“src21”、“src22”));
Observable src3=Observable.just(makeMatrix(Arrays.asList(“src31”、“src32”、“src33”));
Observable src4=Observable.just(makeMatrix(Arrays.asList(“src41”)、Arrays.asList(“src51”);
//准备转换和处理器
列表转换=数组.asList(新转换(1100),新转换(2,0));
处理器处理器=间谍(新处理器());
//表演
//海螺源
可观察阶段=可观察的合并(src1、src2、src3、src4);
//将个体合并到矩阵中
//(#1)在没有累加器的情况下是否可以写入reduce操作?
最终列表收集器=新的ArrayList();
Single combinedData=stage.reduce(收集器,(列表,项目)->{
列表。添加所有(项目);
退货清单;
});
//转化
stage=combinedData.toObservable();
for(变换t:变换){
//(#2)一系列变换是否可以顺序应用于单个(列表),而不使用for循环?
stage=stage.flatMap(t::applyAsync);
}
//过程
stage.doOnComplete(完成:倒计时)
.subscribeOn(Schedulers.computation())
.subscribe(o->System.out.println(processor.printList(o));
//等待处理完成
完成。等待();
//断言
//源应组合在单个矩阵中
@抑制警告(“未选中”)
ArgumentCaptor resultCaptor=ArgumentCaptor.forClass(List.class);
验证(处理器,次(1)).printList(resultCaptor.capture());
List resultMatrix=resultCaptor.getValue();
//结果矩阵不应为空,所有转换应按顺序应用(T1、T2等)
断言(resultMatrix,notNullValue());
断言(resultMatrix.stream().flatMap(Collection::stream).collect(Collectors.toList()),everyItem(containssString(“T1-T2”);
资产(resultMatrix,非(hasItem)(hasItem(containssString(“T2-T1”;)))));
}
私有列表生成矩阵(列表项){
返回集合。单件列表(项目);
}
私有列表生成矩阵(列表项,列表项){
返回数组.asList(items,moreItems);
}
静态类处理器{
字符串打印列表(列表输入){
返回input.stream().map(行->行.stream().collect(收集器.连接(“|”))
.collect(收集器.joining(System.lineSeparator());
}
}
静态类变换{
最终整数n;
私人最终整数延迟;
变换(整数n,整数延迟){
这个,n=n;
延迟=延迟;
}
私有可观察ApplySync(列表输入){
返回Observable.just(input).map(this::apply).delay(delay,TimeUnit.ms);
}
私有列表应用(列表输入){
返回input.stream()
.map(行->行.stream()
.map(this::transform)
.collect(收集器.toList())
)
.collect(Collectors.toList());
}
私有字符串转换(字符串输入){
返回输入+“-T”+n;
}
}
}
如果要运行,请导入以下Maven依赖项:
<dependency>
<groupId>io.reactivex.rxjava2</groupId>
<artifactId>rxjava</artifactId>
<version>2.1.0</version>
</dependency>
<dependency>
<groupId>org.hamcrest</groupId>
<artifactId>hamcrest-all</artifactId>
<version>1.3</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
<version>2.4.3</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.testng</groupId>
<artifactId>testng</artifactId>
<version>6.10</version>
<scope>test</scope>
</dependency>
io.reactivex.rxjava2
rxjava
2.1.0
org.hamcrest
汉克雷斯特酒店
1.3
测试
org.mockito
莫基托磁芯
2.4.3
测试
org.testng
testng
6.10
测试
免责声明:我没有任何特定于RxJava的经验,只有RxJS、Rx.NET和RxSwift
1.
您应该能够直接传递ArrayList
的新实例:
Single<List<List<String>>> combinedData = stage.reduce(new ArrayList<>(), (list, items) -> {
list.addAll(items);
return list;
});
Single combinedData=stage.reduce(新的ArrayList(),(列表,项)->{
列表。添加所有(项目);
退货清单;
});
它将仅用作蓄能器的初始种子;在第一次打电话到洛杉矶之后
Single<List<List<String>>> combinedData = stage.reduce(new ArrayList<>(), (list, items) -> {
list.addAll(items);
return list;
});
// Put this somewhere
public IObservable<List<List<String>> handleTransforms(
Observable<List<List<String>>> currentStage
List<Transform> ts){
return currentStage.flatMap(t[0]::applyAsync)
.flatMap(newStage -> handleTransforms(newStage, ts.stream().skip(1).toList()))
}
// And then use it like this
stage = handleTransforms(stage, transforms);