Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/336.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
在提供给flatMap的RxJava Func1对象中使用可变状态是一个好主意吗?_Java_Rx Java_Reactive Programming - Fatal编程技术网

在提供给flatMap的RxJava Func1对象中使用可变状态是一个好主意吗?

在提供给flatMap的RxJava Func1对象中使用可变状态是一个好主意吗?,java,rx-java,reactive-programming,Java,Rx Java,Reactive Programming,假设我们需要以一种我们需要知道它之前发射的所有项目的方式来转换一个热可观测对象,以便能够确定下一步发射什么。我发现最方便的解决方案是将Func1子类的一个实例传递给flatMap,该子类具有全局状态(例如,映射或以前发出的项列表)。在每次调用中,Func1实例都会更新其状态,并在此基础上决定返回什么 然而,我担心这个解决方案的“精确性”。据我所知,RxJava不适合全局和可变状态,这一解决方案似乎与之相反。另一方面,我确信我的Observable实现了Observable契约,因此它似乎至少是一

假设我们需要以一种我们需要知道它之前发射的所有项目的方式来转换一个热可观测对象,以便能够确定下一步发射什么。我发现最方便的解决方案是将Func1子类的一个实例传递给flatMap,该子类具有全局状态(例如,映射或以前发出的项列表)。在每次调用中,Func1实例都会更新其状态,并在此基础上决定返回什么

然而,我担心这个解决方案的“精确性”。据我所知,RxJava不适合全局和可变状态,这一解决方案似乎与之相反。另一方面,我确信我的Observable实现了Observable契约,因此它似乎至少是一个有效的解决方案,如果可以同时调用事件,那么同步将解决问题

其他可能的解决办法可以是:

  • 创建一个操作符。我想,运算符中的可变状态是允许的。无论如何,我尽量避免使用自定义运算符,因为它们更复杂

  • 通过扫描传播可观察的历史(在列表或地图中)。我要么对每个发出的项使用相同的对象(列表或映射),这会将一个可变对象引入流中,要么每次都复制整个对象,这会浪费大量性能

  • 订阅原始可观察对象,修改订阅对象的某些全局状态,并使用此全局状态发出主题(转换后的可观察对象)上的项目。我考虑过这一点,因为当它处理全局状态(和同步)时,它似乎退出了RxJava的范围

  • 因此,问题是:我是否应该在flatMap中使用具有可变状态的Func1实现来根据以前发出的项的历史(顺便说一句,这是可行的)转换项,如果不可行,我应该使用什么替代方案?总的来说,我对处理复杂多变状态的推荐方法感到困惑,而这种复杂多变的状态是转换可观测数据所必需的


    我希望我已经清楚地表达了我的问题。否则,请让我知道,我将尝试通过一些特定问题和代码来描述它。

    对于有用的工作,可变状态和共享的可变状态通常是必需的。问题是我们如何将易变性与外界隔离开来

  • 创建操作符会隐藏操作符实例中的易变性。缺点是,国家对可观察链是私有的
  • 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);