Java 在未读取所有元素时清理Iterable
让我的脚在RxJava上湿透。我有一个实现Iterable的类,我想将其转换为Observable。使用Observable.from似乎很容易。但是,我需要设置并删除在迭代器中为我提供下一个条目的代码 当我运行整个序列时,这很容易。我添加了对hasNext函数的调用,当没有next时,我运行拆卸。然而,我想使用的一个非常有前途的操作符是takesomeNumber。如果在迭代器耗尽项之前停止执行,则清理代码永远不会运行 我能做些什么来运行我的清理工作?如果使用fromIterable以外的其他东西,我同意。我现在还停留在Java6上。为了说明我的困境,我创建了一个最小的示例: 更新:基于不将迭代器和Iterable混合在一起的反馈,我更新了下面的代码。要理解原始答案,请参阅 更新的测试代码仍然不正确:Java 在未读取所有元素时清理Iterable,java,rx-java,reactive-programming,java-6,Java,Rx Java,Reactive Programming,Java 6,让我的脚在RxJava上湿透。我有一个实现Iterable的类,我想将其转换为Observable。使用Observable.from似乎很容易。但是,我需要设置并删除在迭代器中为我提供下一个条目的代码 当我运行整个序列时,这很容易。我添加了对hasNext函数的调用,当没有next时,我运行拆卸。然而,我想使用的一个非常有前途的操作符是takesomeNumber。如果在迭代器耗尽项之前停止执行,则清理代码永远不会运行 我能做些什么来运行我的清理工作?如果使用fromIterable以外的其他
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.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;
}
}
可移植性:
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真正的问题似乎是:
当底层代码需要设置/拆卸时,我可以使用什么构造来创建一个可观察的对象,特别是当人们期望并非所有元素都被提取时。Iterable只是我的第一个想法
更新2:根据Dave的回答,我提出了我的工作解决方案。迭代器并不完美,但它只是一个开始 如果需要这种控件,则需要将Iterable的实现与迭代器分开。Iterable意味着该类可以提供一个迭代器,该迭代器以对该类有意义的任何方式都是有意义的 但是,如果您在同一个类中实现迭代器,那么您就只能为每个complexDobject实例使用一个迭代器。正确的方法是实施
class FancyObjectIterator implements Iterator<FancyObject>
{
...
}
与complexDobject分开,因此在使用完部分使用的迭代器后,您只需丢弃它们。复杂对象应该只实现Iterable
如果您反对这种方法,因为迭代器有更多需要特殊清理的状态,那么您的设计有问题。迭代器应该知道的唯一状态是基集合中的当前位置,因为集合和位置的定义非常松散,因为迭代器的概念可以应用于比典型集合多得多的集合。如果需要这种控制,则需要将Iterable的实现与迭代器分开。Iterable意味着该类可以提供一个迭代器,该迭代器以对该类有意义的任何方式都是有意义的 但是,如果您在同一个类中实现迭代器,那么您就只能为每个complexDobject实例使用一个迭代器。正确的方法是实施
class FancyObjectIterator implements Iterator<FancyObject>
{
...
}
与complexDobject分开,因此在使用完部分使用的迭代器后,您只需丢弃它们。复杂对象应该只实现Iterable
如果您反对这种方法,因为迭代器有更多需要特殊清理的状态,那么您的设计有问题。迭代器应该知道的唯一状态是基集合中的当前位置,因为集合和位置的定义非常松散,因为迭代器的概念可以应用于比典型集合多得多的集合。您不能同时实现迭代器和Iterable,因为Iterable.iterator必须在每次调用中返回一个新的迭代器
允许代码并行多次迭代相同的Iterable
示例:在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");
}
}
这里使用的增强for循环都将使用迭代器
如您所见,每个迭代器都必须保持自己的独立位置。因此,迭代器方法需要返回一个具有自己状态的新对象
对于您关于清理代码的问题,迭代器没有close方法。迭代器状态不应要求清除。如果它们是绝对必须的,那么终结器可以完成这项工作,但调用终结器可能需要很长时间。终结器的一般建议是:不要。不能同时实现Iterator和Iterable,因为Iterable.Iterator必须在每次调用时返回一个新的迭代器
允许代码并行多次迭代相同的Iterable
示例:在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");
}
}
这里使用的增强for循环都将使用迭代器
如您所见,每个迭代器都必须保持自己的独立位置。因此,迭代器方法需要返回一个具有自己状态的新对象
对于您关于清理代码的问题,迭代器没有close方法。迭代器状态不应要求清除。如果它们是绝对必须的,那么终结器可以完成这项工作,但调用终结器可能需要很长时间。终结器的一般建议是:不要。可观察。使用是
用于在终止完成或错误或取消订阅时拆除。要使用它,您需要使分解代码可访问,以便您的源代码可以如下所示:
source = Observable.using(
resourceFactory,
observableFactory,
resourceDisposer);
source = Observable.using(
() -> new ComplicatedObject(),
co -> Observable.from(co),
co -> co.tearDown());
您的代码可能如下所示:
source = Observable.using(
resourceFactory,
observableFactory,
resourceDisposer);
source = Observable.using(
() -> new ComplicatedObject(),
co -> Observable.from(co),
co -> co.tearDown());
Observable.using用于在终止完成或错误或取消订阅时拆除。要使用它,您需要使分解代码可访问,以便您的源代码可以如下所示:
source = Observable.using(
resourceFactory,
observableFactory,
resourceDisposer);
source = Observable.using(
() -> new ComplicatedObject(),
co -> Observable.from(co),
co -> co.tearDown());
您的代码可能如下所示:
source = Observable.using(
resourceFactory,
observableFactory,
resourceDisposer);
source = Observable.using(
() -> new ComplicatedObject(),
co -> Observable.from(co),
co -> co.tearDown());
嗨,吉姆,谢谢你的回复。我把迭代器和Iterable归为最小的例子。我可以把它分开。是的,我的设计可能是错的。我试图解决的是:我有一个需要设置和拆卸的连接。我该如何设计它,以便在我的订阅者有足够的信息而不是我用完信息时进行清理items@stwissel您不需要使用迭代器遍历需要清理的内容。Iterable和Iterator用于可多次遍历的对象,这意味着它们在内存结构中工作。嗨,Andreas,好吧,那么如果Iterable用于需要清理的可观察创建,我有什么选择?@stwissel可观察创建意味着什么?@Andreas:很抱歉不清楚。我的意思是:如果创建/使用一个需要设置/拆卸的Iterable不是一个好主意,那么我需要其他东西来创建我的Observable。我的目标是可观察的。我愿意以任何明智的方式到达那里。Observable.fromIterable看起来是一个潜在的方法,直到你解释了为什么学习Hi Jim不是那么开心,谢谢你的回答。我把迭代器和Iterable归为最小的例子。我可以把它分开。是的,我的设计可能是错的。我试图解决的是:我有一个需要设置和拆卸的连接。我该如何设计它,以便在我的订阅者有足够的信息而不是我用完信息时进行清理items@stwissel您不需要使用迭代器遍历需要清理的内容。Iterable和Iterator用于可多次遍历的对象,这意味着它们在内存结构中工作。嗨,Andreas,好吧,那么如果Iterable用于需要清理的可观察创建,我有什么选择?@stwissel可观察创建意味着什么?@Andreas:很抱歉不清楚。我的意思是:如果创建/使用一个需要设置/拆卸的Iterable不是一个好主意,那么我需要其他东西来创建我的Observable。我的目标是可观察的。我愿意以任何明智的方式到达那里。Observable.fromIterable看起来像是一种潜在的方法——直到你解释了为什么学习Hi Andreas不是那么开心,谢谢你的回答。似乎我需要重新表述我的示例,这样不是每个人都会跳到“不实现迭代器”和“iterable”这两个词上。是的->终结器不是一个好主意AHI Andreas,谢谢回复。似乎我需要重新表述我的示例,这样不是每个人都会跳到“不实现迭代器”和“iterable”这两个词上。是的->终结器不是一个好主意我假设源是我订阅的?现在我只需要把它翻译回Java6-是的。将是可见的。顺便说一下,Eclipse>=4.5将使用鼠标右键自动转换到匿名类。什么IDE?老式Eclipse与老式Java相匹配-但我应该学习当前的Eclipse版本。我不喜欢匿名函数。我知道你的意思,我宁愿给它们命名,以保持可读性和可调试性!我想来源就是我订阅的?现在我只需要把它翻译回Java6-是的。将是可见的。顺便说一下,Eclipse>=4.5将使用鼠标右键自动转换到匿名类。什么IDE?老式Eclipse与老式Java相匹配-但我应该学习当前的Eclipse版本。我不喜欢匿名函数。我知道你的意思,我宁愿给它们命名,以保持可读性和可调试性!