Java 在未读取所有元素时清理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以外的其他

让我的脚在RxJava上湿透。我有一个实现Iterable的类,我想将其转换为Observable。使用Observable.from似乎很容易。但是,我需要设置并删除在迭代器中为我提供下一个条目的代码

当我运行整个序列时,这很容易。我添加了对hasNext函数的调用,当没有next时,我运行拆卸。然而,我想使用的一个非常有前途的操作符是takesomeNumber。如果在迭代器耗尽项之前停止执行,则清理代码永远不会运行

我能做些什么来运行我的清理工作?如果使用fromIterable以外的其他东西,我同意。我现在还停留在Java6上。为了说明我的困境,我创建了一个最小的示例:

更新:基于不将迭代器和Iterable混合在一起的反馈,我更新了下面的代码。要理解原始答案,请参阅

更新的测试代码仍然不正确:

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版本。我不喜欢匿名函数。我知道你的意思,我宁愿给它们命名,以保持可读性和可调试性!