说我有3个条件要检查。在命令式编程中,我会写
boolean foo(A a, B b, C c){
if(a.meetsCriteria()){ return true; }
if(b.meetsCriteria()){ return true; }
if(c.meetsCriteria()){ return true; }
return false;
}
这是我将上述内容转换为被动
的愚蠢行为Observable<Boolean> foo(A a, B b, C c){
Observable.zip(
a.meetsCriteria(),
b.meetsCriteria(),
c.meetsCriteria(),
(bool1, bool2, bool3)->{return bool1 | bool2 | bool3;}
}
这里的问题是调用了所有3个meetsCriteria()
方法,因此这种实现不会急切地返回。我希望B和C&#39; meetsCriteria()
在A.meetsCriteria()
返回true时不执行。正确的反应转换是什么?
答案 0 :(得分:0)
你只需要另一个操作员。而不是Observable.zip
,您可以使用一系列flatMaps:
a.meetsCriteria().flatMap(
resa -> resa ? Observable.just(true) : b.meetsCriteria().flatMap(
resb -> resb ? Observable.just(true) : c.meetsCriteria()
)
)
然而,这基本上会使代码串行在最坏的情况下(所有三个标准都是假的)。
因此,要从反应式编程中受益,您必须立即运行所有这些。我提出了以下想法:
merge
观察者(他们将并行运行)filter
其中任何一个发出的true
个值defaultIfEmpty(false)
运算符,这是所有可观测量发出的情况的后备false
first()
,这样我们就可以得到一个布尔值。你可以自己试试:
Observable<Boolean> a = Observable.just(false).delay(15, TimeUnit.SECONDS);
Observable<Boolean> b = Observable.just(true).delay(5, TimeUnit.SECONDS);
Observable<Boolean> c = Observable.just(false).delay(50, TimeUnit.DAYS);
final Observable<Boolean> res = Observable.merge(a, b, c)
.filter(item -> item == true)
.defaultIfEmpty(false)
.first();
System.err.println(res.toBlocking().first());
在我的机器上运行大约5
秒,这正是可观察b
需要发出true
的时间。但是,如果你这样做:
Observable<Boolean> b = Observable.just(false).delay(5, TimeUnit.SECONDS);
,你注定要等待50天,观察c
完成:)嗯,显然无法知道c
是否会为合并运算符发出任何内容,所以这是不可避免的。
当然,如果你尝试,你仍然可以从并行性中受益:
Observable<Boolean> a = Observable.just(false).delay(10, TimeUnit.SECONDS);
Observable<Boolean> b = Observable.just(false).delay(10, TimeUnit.SECONDS);
Observable<Boolean> c = Observable.just(false).delay(10, TimeUnit.SECONDS);
,总运行时间约为10秒,而不是串行版本的30秒。
P.S。也提出了另一种解决方案,我觉得它更自然。希望代码不言自明:
final Observable<Boolean> res = Observable.combineLatest(
a.startWith((Boolean)null),
b.startWith((Boolean)null),
c.startWith((Boolean)null),
(Boolean b1, Boolean b2, Boolean b3) -> {
// note that b1/b2/b3 might be null
// we interpret that as 'unfinished' computation
if (Boolean.TRUE.equals(b1) || Boolean.TRUE.equals(b2) || Boolean.TRUE.equals(b3)) {
// if any of source observables has finished and was true, the result is obviously true
return true; }
if (Boolean.FALSE.equals(b1) && Boolean.FALSE.equals(b2) && Boolean.FALSE.equals(b3)) {
// if all of source observables have finished and are false, the result is false
return false;
}
return null; // otherwise we're in some kind of intermediate state
}
)
.filter(item -> item != null)
.first();
答案 1 :(得分:0)
return Observable.concatMap(
a.meetsCriteria(),
b.meetsCriteria(),
c.meetsCriteria())
.filter(value -> value)
.takeFirst();