在RxJava上弄湿我的脚。我有一个实现Iterable
的类我要转换为Observable
。使用Observable.from()
似乎很容易。但是,我需要设置和拆除为我提供单个条目的代码(迭代器中的next()
。
当我浏览整个序列时,这很容易。我添加了对hasNext()
函数的调用,当没有下一个函数时,我运行了拆解。然而,我想要使用的一个非常有前景的运算符是take(someNumber)
。如果在Iterator用完项目之前停止,则清理代码永远不会运行。
我可以做些什么来清理我的运行?如果使用的不是from(Iterable)
,我就可以了。我现在坚持使用Java6。为了说明我的困境,我创建了一个最小的样本:
更新:根据不将Iterator和Iterable混合在一起的反馈,我更新了下面的代码。要了解原始答案,请original code is in that gist。
更新了测试代码(仍然不错):
import rx.Observable;
import rx.functions.Action0;
import rx.functions.Action1;
/**
* @author stw
*
*/
public class RXTest {
/**
* @param args
*/
public static void main(String[] args) {
ComplicatedObject co = new ComplicatedObject();
Observable<FancyObject> fancy = Observable.from(co);
// if the take is less than the elements cleanup never
// runs. If you take the take out, cleanup runs
fancy.take(3).subscribe(
new Action1<FancyObject>() {
public void call(FancyObject item) {
System.out.println(item.getName());
}
},
new Action1<Throwable>() {
public void call(Throwable error) {
System.out.println("Error encountered: " + error.getMessage());
}
},
new Action0() {
public void call() {
System.out.println("Sequence complete");
}
}
);
}
}
花哨的对象:
import java.util.Date;
import java.util.UUID;
/**
* @author stw
*
*/
public class FancyObject {
private String name = UUID.randomUUID().toString();
private Date created = new Date();
public String getName() {
return this.name;
}
public void setName(String name) {
this.name = name;
}
public Date getCreated() {
return this.created;
}
public void setCreated(Date created) {
this.created = created;
}
}
迭代器:
import java.util.Iterator;
/**
* @author stw
*
*/
public class FancyIterator implements Iterator<FancyObject> {
private final ComplicatedObject theObject;
private int fancyCount = 0;
public FancyIterator(ComplicatedObject co) {
this.theObject = co;
}
public boolean hasNext() {
return this.theObject.hasObject(this.fancyCount);
}
public FancyObject next() {
FancyObject result = this.theObject.getOne(this.fancyCount);
this.fancyCount++;
return result;
}
}
The Iterable:
import java.util.Iterator;
import java.util.Vector;
/**
* @author stw
*
*/
public class ComplicatedObject implements Iterable<FancyObject> {
private boolean isInitialized = false;
Vector<FancyObject> allOfThem = new Vector<FancyObject>();
public Iterator<FancyObject> iterator() {
return new FancyIterator(this);
}
public boolean hasObject(int whichone) {
if (!this.isInitialized) {
this.setupAccesstoFancyObject();
}
return (whichone < this.allOfThem.size());
}
public FancyObject getOne(int whichone) {
if (!this.isInitialized) {
this.setupAccesstoFancyObject();
}
if (whichone < this.allOfThem.size()) {
return this.allOfThem.get(whichone);
}
// If we ask bejond...
this.isInitialized = false;
this.teardownAccessToFancyObjects();
return null;
}
private void setupAccesstoFancyObject() {
System.out.println("Initializing fancy objects");
for (int i = 0; i < 20; i++) {
this.allOfThem.addElement(new FancyObject());
}
this.isInitialized = true;
}
private void teardownAccessToFancyObjects() {
System.out.println("I'm doing proper cleanup here");
}
}
但真正的问题(thx @Andreas)似乎是:
当底层代码需要设置/拆除时,我可以使用什么构造来创建Observable
,尤其是当人们期望不是所有元素都被拉出时。 Iterable
只是我的第一个想法
更新2 :根据Dave的回答I created a gist和我的工作解决方案。迭代器并不完美,但它是一个开始。
答案 0 :(得分:2)
如果您需要这种控制,则需要将Iterable
的实施与Iterator
分开。 Iterable
表示该类可以提供一个Iterator
,它对于该类有意义的任何方式都是有意义的。
但是,如果您在同一个班级中实施Iterator
,那么您只会为Iterator
的每个实例只有一个ComplicatedObject
。正确的方法是实施
class FancyObjectIterator implements Iterator<FancyObject>
{
...
}
与ComplicatedObject
分开,因此您只需在完成它们时就丢弃部分使用的迭代器。 ComplicatedObject
应仅实施Iterable<FancyObject>
。
如果您反对该方法,因为迭代器具有更多需要特殊清理的状态,那么您的设计就会出现问题。 Iterator
应该注意的唯一状态是基础“集合”中的当前位置,因为迭代器的概念可以应用于典型的“集合”和“位置”的非常宽松的定义。集合。
答案 1 :(得分:2)
Observable.using
用于拆除终止(完成或错误)或取消订阅。要使用它,您需要使拆卸代码可访问,以便您的源可观察对象如下所示:
source = Observable.using(
resourceFactory,
observableFactory,
resourceDisposer);
使用您的代码可能如下所示:
source = Observable.using(
() -> new ComplicatedObject(),
co -> Observable.from(co),
co -> co.tearDown());
答案 2 :(得分:1)
您无法同时实施Iterator
和Iterable
,因为Iterable.iterator()
必须返回新 Iterator
或每次通话。
允许代码并行多次迭代相同的Iterable
。
示例:在Iterable
中找到重复元素的过于简化的方法:
Iterable<MyObject> myIterable = ...;
for (MyObject myObj1 : myIterable) {
for (MyObject myObj2 : myIterable) {
if (myObj1 != myObj2 && myObj1.equals(myObj2)) {
// found duplicate
}
}
}
此处使用的增强型for
循环将分别使用Iterator
。
如您所见,每个Iterator
必须保持自己的独立位置。因此,iterator()
方法需要返回一个具有自己状态的新对象。
关于清理代码的问题,Iterator
没有close()
方法。迭代器状态不应该要求清理。如果他们绝对必须,终结器可以做到,但终结器可能需要非常长时间来调用。终结者的一般建议是:不要。