在提供给flatMap的RxJava Func1对象中使用可变状态是一个好主意吗?
假设我们需要以一种我们需要知道它之前发射的所有项目的方式来转换一个热可观测对象,以便能够确定下一步发射什么。我发现最方便的解决方案是将Func1子类的一个实例传递给flatMap,该子类具有全局状态(例如,映射或以前发出的项列表)。在每次调用中,Func1实例都会更新其状态,并在此基础上决定返回什么 然而,我担心这个解决方案的“精确性”。据我所知,RxJava不适合全局和可变状态,这一解决方案似乎与之相反。另一方面,我确信我的Observable实现了Observable契约,因此它似乎至少是一个有效的解决方案,如果可以同时调用事件,那么同步将解决问题 其他可能的解决办法可以是:在提供给flatMap的RxJava Func1对象中使用可变状态是一个好主意吗?,java,rx-java,reactive-programming,Java,Rx Java,Reactive Programming,假设我们需要以一种我们需要知道它之前发射的所有项目的方式来转换一个热可观测对象,以便能够确定下一步发射什么。我发现最方便的解决方案是将Func1子类的一个实例传递给flatMap,该子类具有全局状态(例如,映射或以前发出的项列表)。在每次调用中,Func1实例都会更新其状态,并在此基础上决定返回什么 然而,我担心这个解决方案的“精确性”。据我所知,RxJava不适合全局和可变状态,这一解决方案似乎与之相反。另一方面,我确信我的Observable实现了Observable契约,因此它似乎至少是一
我希望我已经清楚地表达了我的问题。否则,请让我知道,我将尝试通过一些特定问题和代码来描述它。对于有用的工作,可变状态和共享的可变状态通常是必需的。问题是我们如何将易变性与外界隔离开来
scan()
、reduce()
和fold()
(如果存在)都是不错的选择,但它们的实现非常有限,以不明显的方式导出它们的状态,并且还限于它们所连接的可观察链主题
或中继
对象提供了有用的切点回到基础上来,以线程安全的方式使用私有可访问的数据结构并不是一件坏事。如果您只关心一个观察者链,那么选项1或3中的任何一个都可以很容易地完成这项工作。通常不建议使用包含可变状态的函数流,因为可变状态可能会在多个
订阅者之间共享到特定的可观察的链。然而,大多数开发人员在需要时组装observatable
s,很少重用相同的observatable
。例如,一个按钮点击处理程序将创建一个Observable
,通过组合,它分叉出另外两个Observable
s以异步地从两个不同的地方获取数据,然后订阅这个线程本地Observable
实例。新的按钮点击将以全新且独立的可观察的重复该过程
下面是有状态函数问题的解决方案:使有状态位的存在取决于订阅的各个订户:defer()
Observable o=可观察。延迟(()->{
返回可观测范围(1,10)
.map(新函数1(){
整数和;
@凌驾
公共整数调用(整数v){
总和+=v;
回报金额;
}
});
});
o、 订阅(System.out::println);
o、 订阅(System.out::println);
由于将为每个subscribe
调用创建Func1
内部类,因此其sum
字段将是每个消费者的本地字段。还请注意,sum
被返回并自动装箱为一个不可变的整数
,然后可以在其他线程中自由读取该整数(想想observeOn
),因为它随后与sum
字段完全分离,然后打开。使用#2。如果只能从操作符内部访问,则它不是可变状态。使用#scan,您不需要担心列表的易变性,因为没有其他线程可以同时访问它。例如,scan(ArrayList::new,(aList,elementFromUpstream)->{…}scan()
通常以不太有用的方式(包括跨线程边界)与可观察对象的每个订户共享可变状态;您必须考虑在同一订阅链上的不同线程上运行的阶段,即使只有一个最终订阅方可观察到。Scan有一些变量,它们采用每个订阅者的初始状态,但该值仍然必须是有效不变的。
Observable<Integer> o = Observable.defer(() -> {
return Observable.range(1, 10)
.map(new Func1<Integer, Integer>() {
int sum;
@Override
public Integer call(Integer v) {
sum += v;
return sum;
}
});
});
o.subscribe(System.out::println);
o.subscribe(System.out::println);