有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

关闭java的资源。util。迭代器

我已经实现了一个定制的java。util。迭代器使用一个应该在最后使用close()方法释放的资源。该资源可以是java。sql。结果集,一个java。木卫一。输入流

public interface CloseableIterator<T> extends Iterator<T>
  {
  public void close();
  }

某些使用此迭代器的外部库可能不知道必须关闭它。e、 g:

public boolean isEmpty(Iterable<T> myiterable)
 {
 return myiterable.iterator().hasNext();
 }

在这种情况下,是否有方法关闭此迭代器

更新:非常感谢当前的答案。我会给每个人一个(+1)。当hasNext()返回false时,我确实已经关闭了迭代器。我的问题是循环迭代在上一次迭代之前中断,如我的示例所示


共 (6) 个答案

  1. # 1 楼答案

    只需定义自己的迭代器子接口,其中包含一个close方法,并确保使用它而不是常规的迭代器类。例如,创建以下界面:

    import java.io.Closeable;
    import java.util.Iterator;
    
    public interface CloseableIterator<T> extends Iterator<T>, Closeable {}
    

    然后一个实现可能是这样的:

    List<String> someList = Arrays.asList( "what","ever" );
    final Iterator<String> delegate = someList.iterator();
    return new CloseableIterator<String>() {
        public void close() throws IOException {
            //Do something special here, where you have easy
            //access to the vars that created the iterator
        }
    
        public boolean hasNext() {
            return delegate.hasNext();
        }
    
        public String next() {
            return delegate.next();
        }
    
        public void remove() {
            delegate.remove();
        }
    };
    
  2. # 2 楼答案

    在您的实现中,如果迭代器耗尽,您可以自己关闭它

    public boolean hasNext() {
           .... 
           if( !hasNext ) {
               this.close();
           }
           return hasNext;
     }
    

    并清楚地记录:

    This iterator will invoke close() when hasNext() return false, if you need to dispose the iterator before make sure you call close your self

    例如:

    void testIt() {
         Iterator i = DbIterator.connect("db.config.info.here");
         try {
              while( i.hasNext() {
                  process( i.next() );
              }
          } finally {
              if( i != null )  {
                  i.close();
              }
          }
      }
    

    顺便说一句,你可以在那里实现Iterable并使用增强的for循环

  3. # 3 楼答案

    创建一个自定义迭代器来实现AutoCloseable interface

    public interface CloseableIterator<T> extends Iterator<T>, AutoCloseable {
    }
    

    然后在try with resource statement中使用这个迭代器

    try(CloseableIterator iterator = dao.findAll()) {
        while(iterator.hasNext()){
           process(iterator.next());
        }
    }
    

    无论发生什么情况,此模式都将关闭基础资源: -声明完成后 -即使抛出异常

    最后,清楚地记录必须如何使用这个迭代器

    如果您不想委派接近通话,请使用推送策略。例如,使用java 8 lambda:

    dao.findAll(r -> process(r));
    
  4. # 4 楼答案

    你可以在finalizer内关闭它,但它不会给你想要的行为。只有当垃圾收集器希望清理对象时,才会调用终结器,这样您的资源可能会保持打开状态。更糟糕的是,如果有人抓住你的迭代器,它永远不会关闭

    在第一次调用hasNext()时,可能会关闭流,该调用返回false。这仍然不能保证做到这一点,因为有人可能只迭代第一个元素,再也不用担心它了

    真的,我认为在处理外部库时,你需要自己管理它。您将对使用iterable的方法进行这些调用,那么为什么不在完成后自己关闭它呢?资源管理不是你可以强加给一个不知道更好的外部库的东西

  5. # 5 楼答案

    问题是结尾处的条件。我们经常迭代一个完整的集合或数据集,所以我们现在没有数据可读了

    但是如果我们在到达数据末尾之前设置一个中断循环,迭代器就不会结束,也不会关闭

    一种解决方法是在构造期间将数据源的内容缓存在迭代器中,然后关闭资源。因此,迭代器不会处理打开的资源,而是处理缓存的数据

  6. # 6 楼答案

    我在一个使用迭代器(比如对象流)的项目中遇到了类似的问题。为了说明迭代器没有被完全使用的时间,我还需要一个close方法。 起初,我只是扩展了迭代器和可关闭接口,但深入挖掘了java 1.7中引入的try with resources语句,我认为它提供了一种简洁的实现方式

    您可以扩展迭代器和自动关闭接口,实现Close方法,并使用迭代器尝试使用资源。 一旦迭代器超出范围,运行时将为您调用close

    https://docs.oracle.com/javase/7/docs/api/java/lang/AutoCloseable.html

    https://docs.oracle.com/javase/tutorial/essential/exceptions/tryResourceClose.html

    比如

    接口: public interface MyIterator<E> extends Iterator<E>, AutoCloseable { }

    它的实现:` 公共类MyIteratorImpl实现MyIterator{

    private E nextItem = null;
    
    @Override
    public boolean hasNext() {
        if (null == nextItem)
            nextItem = getNextItem();
    
        return null != nextItem;
    }
    
    @Override
    public E next() {
        E next = hasNext() ? nextItem : null;
        nextItem = null;
        return next;
    }
    
    @Override
    public void close() throws Exception {
        // Close off all your resources here, Runtime will call this once 
           Iterator out of scope.
    }
    
    private E getNextItem() {
        // parse / read the next item from the under laying source.
        return null;
    }
    

    } `

    还有一个将其与try-with资源一起使用的示例:

    ` 公共类MyIteratorConsumer{

    /**
     * Simple example of searching the Iterator until a string starting 
     *  with the given string is found.
     * Once found, the loop stops, leaving the Iterator partially consumed.
     * As 'stringIterator' falls out of scope, the runtime will call the 
     * close method on the Iterator.
     * @param search the beginning of a string
     * @return The first string found that begins with the search
     * @throws Exception 
     */
    public String getTestString(String search) throws Exception {
        String foundString = null;
    
        try (MyIterator<String> stringIterator = new MyIteratorImpl<>()) {
            while (stringIterator.hasNext()) {
                String item = stringIterator.next();
                if (item.startsWith(search)) {
                    foundString = item;
                    break;
                }
            }
    
        }
        return foundString;
    }
    

    } `