如何在不使用reduce()或last()折叠的情况下获取Flux的最后一项?这是我的用例:
1)我有一个根据状态产生Flux<T>
的生成器。
2)内部Flux
完成后,它将更改影响我在生成器中发出的下一个Flux
对象的状态。
示意图看起来像这样
static class State {
int secret = 2;
int iteration = 0;
}
Random rand = new Random(1024);
Flux<Integer> stream = Flux.<Flux<Integer>, State>generate(State::new, (state, sink) -> {
System.out.println(String.format("Generate: %d", state.secret));
Flux<Integer> inner = Flux.range(1, rand.nextInt(10));
sink.next(inner.doOnComplete(() -> {
// How do I get last item of `inner` here ?
// For example I'd like to decrement `state.secret` by last value of `inner`
}));
return state;
}).flatMap(Function.identity());
UPD:我未标记我的答案,因为事实证明该黑客是不可靠的。可能会在完全消耗之前的.generate()
之前调用Flux
,从而使last
中的值不正确。
答案 0 :(得分:0)
第一个版本不可靠。我砍了另一个:
static <T> Flux<T> expandOnLastItem(Supplier<Flux<T>> seed, Function<T, Flux<T>> generator) {
return Flux.just(new AtomicReference<T>())
.flatMap(last -> Flux.just(seed.get().materialize())
.flatMap(Function.identity())
.expand(v -> {
if (v.hasValue()) {
last.set(v.get());
} else if (v.isOnComplete() && last.get() != null) {
Flux<T> res = generator.apply(last.get());
last.set(null);
return res.materialize();
}
return Flux.empty();
})
.filter(s -> !s.isOnComplete())
.dematerialize());
}
可以用作
static Flux<Integer> getPage(int pageId, int size) {
return Flux.defer(() -> {
if (pageId < 3) {
System.out.println("Returning data for pageId: " + pageId);
return Flux.range(pageId * 100, size);
} else {
System.out.println("Returning empty for pageId: " + pageId);
return Flux.empty();
}
});
}
expandOnLastItem(
() -> getPage(0, 5),
lastId -> {
System.out.println(" Expanding. Last item: " + lastId);
int curPage = lastId / 100;
return getPage(curPage + 1, 5);
})
.reduce(0L, (count, value) -> {
System.out.println("==> " + value);
return count + 1;
})
.block();
所以我通过在generator中改变状态变量来破解它。它可以工作,但不是很实用。如果其他人可以提出其他建议,我将不胜感激。
Random rand = new Random(1024);
Flux.<Flux<String>, State>generate(State::new, (state, sink) -> {
if (state.iteration < 4) {
final int count = rand.nextInt(10) + 1;
System.out.println(String.format("*** Generate %d: start %d (count %d)", state.iteration, state.secret, count));
Flux<Integer> inner = Flux.range(state.secret, count);
final int[] last = {Integer.MIN_VALUE};
sink.next(
inner
.doOnNext(value -> {
last[0] = value;
})
.map(value -> String.format("Iter %d value %d", state.iteration, value))
.doOnComplete(() -> {
System.out.println(String.format("Inner complete (last item was %d)", last[0]));
state.secret = last[0];
state.iteration += 1;
}));
} else {
System.out.println("Generate complete");
sink.complete();
}
return state;
})
.flatMap(Function.identity())
.map(value -> {
System.out.println(String.format("Ext map: %s", value));
return value;
})
.buffer(5)
.flatMapIterable(Function.identity())
.subscribe(value -> System.out.println(String.format(" ---> %s", value)));
System.out.println("Exiting");