code: package com.beijunyi.parallelgit.filesystem.io;
  
  import java.io.IOException;
  import java.nio.file.ClosedDirectoryStreamException;
  import java.nio.file.DirectoryStream;
  import java.nio.file.Path;
  import java.util.Iterator;
  import java.util.List;
  import java.util.NoSuchElementException;
  import javax.annotation.Nonnull;
  import javax.annotation.Nullable;
  
  import com.beijunyi.parallelgit.filesystem.GitPath;
  
  public class GfsDirectoryStream implements DirectoryStream<Path> {
  
    private final GitPath parent;
    private final List<String> children;
    private final Filter<? super Path> filter;
    private volatile boolean closed = false;
  
    public GfsDirectoryStream(DirectoryNode dir, GitPath parent, @Nullable Filter<? super Path> filter) throws IOException {
      this.parent = parent;
      this.filter = filter;
      children = dir.listChildren();
    }
  
    @Nonnull
    @Override
    public Iterator<Path> iterator() {
      final Iterator<String> childrenIt = children.iterator();
      return new Iterator<Path>() {
  
        private Path next;
  
        private boolean findNext() {
          while(childrenIt.hasNext()) {
            String child = childrenIt.next();
            GitPath childPath = parent.resolve(child);
            try {
              if(filter == null || filter.accept(childPath)) {
                next = childPath;
                return true;
              }
            } catch(IOException ignore) {
            }
          }
          return false;
        }
  
        @Override
        public boolean hasNext() throws ClosedDirectoryStreamException {
          checkNotClosed();
          return next != null || findNext();
        }
  
        @Nonnull
        @Override
        public Path next() throws ClosedDirectoryStreamException, NoSuchElementException {
          checkNotClosed();
          if(next != null || hasNext()) {
            Path ret = next;
            next = null;
            return ret;
          }
          throw new NoSuchElementException();
        }
  
        @Override
        public void remove() throws UnsupportedOperationException {
          throw new UnsupportedOperationException();
        }
      };
    }
  
    @Override
    public void close() throws IOException {
      closed = true;
    }
  
    private void checkNotClosed() throws ClosedDirectoryStreamException {
      if(closed)
        throw new ClosedDirectoryStreamException();
    }
  
  }
  