You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@commons.apache.org by gg...@apache.org on 2022/09/12 19:43:54 UTC

[commons-io] branch master updated: Add IOIterator

This is an automated email from the ASF dual-hosted git repository.

ggregory pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/commons-io.git


The following commit(s) were added to refs/heads/master by this push:
     new e138ea9e Add IOIterator
e138ea9e is described below

commit e138ea9ee451f024031ae7276daeee22e9081d1c
Author: Gary Gregory <ga...@gmail.com>
AuthorDate: Mon Sep 12 12:43:48 2022 -0700

    Add IOIterator
---
 src/changes/changes.xml                            |   2 +-
 .../org/apache/commons/io/function/IOIterator.java | 104 +++++++++++++++++++++
 .../commons/io/function/IOIteratorAdapter.java     |  56 +++++++++++
 .../commons/io/function/UncheckedIOIterator.java   |  59 ++++++++++++
 .../commons/io/function/IOIteratorAdapterTest.java |  88 +++++++++++++++++
 .../apache/commons/io/function/IOIteratorTest.java |  94 +++++++++++++++++++
 6 files changed, 402 insertions(+), 1 deletion(-)

diff --git a/src/changes/changes.xml b/src/changes/changes.xml
index 8e6e8a29..f8d7da7a 100644
--- a/src/changes/changes.xml
+++ b/src/changes/changes.xml
@@ -425,7 +425,7 @@ The <action> type attribute can be add,update,fix,remove.
         Add PathUtils.getLastModifiedFileTime(*).
       </action>
       <action dev="ggregory" type="add" due-to="Gary Gregory">
-        Add IOBiFunction, IOTriFunction, IOQuadFunction, IOPredicate, FilesUncheck.
+        Add IOBiFunction, IOTriFunction, IOQuadFunction, IOPredicate, IOIterator, FilesUncheck.
       </action>
       <action dev="ggregory" type="add" due-to="Gary Gregory">
         Add IOUtils.consume(Reader).
diff --git a/src/main/java/org/apache/commons/io/function/IOIterator.java b/src/main/java/org/apache/commons/io/function/IOIterator.java
new file mode 100644
index 00000000..572a33d3
--- /dev/null
+++ b/src/main/java/org/apache/commons/io/function/IOIterator.java
@@ -0,0 +1,104 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.commons.io.function;
+
+import java.io.IOException;
+import java.io.UncheckedIOException;
+import java.util.Iterator;
+import java.util.NoSuchElementException;
+import java.util.Objects;
+import java.util.function.Consumer;
+
+/**
+ * Like {@link Iterator} but throws {@link IOException}.
+ *
+ * @param <E> the type of elements returned by this iterator.
+ */
+public interface IOIterator<E> {
+
+    /**
+     * Adapts the given Iterator as an IOIterator.
+     *
+     * @param <E> the type of the stream elements.
+     * @param iterator The iterator to adapt
+     * @return A new IOIterator
+     */
+    static <E> IOIterator<E> adapt(final Iterator<E> iterator) {
+        return IOIteratorAdapter.adapt(iterator);
+    }
+
+    /**
+     * Creates an {@link Iterator} for this instance that throws {@link UncheckedIOException} instead of
+     * {@link IOException}.
+     *
+     * @return an {@link UncheckedIOException} {@link Iterator}.
+     */
+    default Iterator<E> asIterator() {
+        return new UncheckedIOIterator<>(this);
+    }
+
+    /**
+     * Like {@link Iterator#forEachRemaining(Consumer)}.
+     *
+     * @param action See delegate.
+     * @throws IOException if an I/O error occurs.
+     */
+    default void forEachRemaining(final IOConsumer<? super E> action) throws IOException {
+        Objects.requireNonNull(action);
+        while (hasNext()) {
+            action.accept(next());
+        }
+    }
+
+    /**
+     * Like {@link Iterator#hasNext()}.
+     *
+     * @return See delegate.
+     * @throws IOException if an I/O error occurs.
+     */
+    boolean hasNext() throws IOException;
+
+    /**
+     * Like {@link Iterator#next()}.
+     *
+     * @return See delegate.
+     * @throws IOException if an I/O error occurs.
+     * @throws NoSuchElementException if the iteration has no more elements
+     */
+    E next() throws IOException;
+
+    /**
+     * Like {@link Iterator#remove()}.
+     *
+     * @throws IOException if an I/O error occurs.
+     */
+    @SuppressWarnings("unused")
+    default void remove() throws IOException {
+        unwrap().remove();
+    }
+
+    /**
+     * Unwraps this instance and returns the underlying {@link Iterator}.
+     * <p>
+     * Implementations may not have anything to unwrap and that behavior is undefined for now.
+     * </p>
+     * @return the underlying Iterator.
+     */
+    Iterator<E> unwrap();
+
+}
diff --git a/src/main/java/org/apache/commons/io/function/IOIteratorAdapter.java b/src/main/java/org/apache/commons/io/function/IOIteratorAdapter.java
new file mode 100644
index 00000000..c650f995
--- /dev/null
+++ b/src/main/java/org/apache/commons/io/function/IOIteratorAdapter.java
@@ -0,0 +1,56 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.commons.io.function;
+
+import java.io.IOException;
+import java.util.Iterator;
+import java.util.Objects;
+
+/**
+ * Adapts an {@link Iterator} as an {@link IOIterator}.
+ *
+ * @param <E> the type of the stream elements.
+ */
+final class IOIteratorAdapter<E> implements IOIterator<E> {
+
+    static <E> IOIteratorAdapter<E> adapt(final Iterator<E> delegate) {
+        return new IOIteratorAdapter<>(delegate);
+    }
+
+    private final Iterator<E> delegate;
+
+    IOIteratorAdapter(final Iterator<E> delegate) {
+        this.delegate = Objects.requireNonNull(delegate, "delegate");
+    }
+
+    @Override
+    public boolean hasNext() throws IOException {
+        return delegate.hasNext();
+    }
+
+    @Override
+    public E next() throws IOException {
+        return delegate.next();
+    }
+
+    @Override
+    public Iterator<E> unwrap() {
+        return delegate;
+    }
+
+}
diff --git a/src/main/java/org/apache/commons/io/function/UncheckedIOIterator.java b/src/main/java/org/apache/commons/io/function/UncheckedIOIterator.java
new file mode 100644
index 00000000..47245261
--- /dev/null
+++ b/src/main/java/org/apache/commons/io/function/UncheckedIOIterator.java
@@ -0,0 +1,59 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.commons.io.function;
+
+import java.io.IOException;
+import java.io.UncheckedIOException;
+import java.util.Iterator;
+import java.util.Objects;
+
+/**
+ * An {@link Iterator} for a {@link IOIterator} that throws {@link UncheckedIOException} instead of {@link IOException}.
+ *
+ * Keep package-private for now.
+ *
+ * @param <E> the type of elements returned by this iterator.
+ */
+final class UncheckedIOIterator<E> implements Iterator<E> {
+
+    private final IOIterator<E> delegate;
+
+    /**
+     * Constructs a new instance.
+     *
+     * @param delegate The delegate
+     */
+    UncheckedIOIterator(final IOIterator<E> delegate) {
+        this.delegate = Objects.requireNonNull(delegate, "delegate");
+    }
+
+    @Override
+    public boolean hasNext() {
+        return Uncheck.get(delegate::hasNext);
+    }
+
+    @Override
+    public E next() {
+        return Uncheck.get(delegate::next);
+    }
+
+    @Override
+    public void remove() {
+        Uncheck.run(delegate::remove);
+    }
+}
diff --git a/src/test/java/org/apache/commons/io/function/IOIteratorAdapterTest.java b/src/test/java/org/apache/commons/io/function/IOIteratorAdapterTest.java
new file mode 100644
index 00000000..d4fa89e3
--- /dev/null
+++ b/src/test/java/org/apache/commons/io/function/IOIteratorAdapterTest.java
@@ -0,0 +1,88 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.commons.io.function;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+import java.io.IOException;
+import java.nio.file.Path;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+
+/**
+ * Tests {@code IOIteratorAdapter}.
+ */
+public class IOIteratorAdapterTest {
+
+    private IOIteratorAdapter<Path> iterator;
+
+    @BeforeEach
+    public void beforeEach() {
+        iterator = IOIteratorAdapter.adapt(newPathList().iterator());
+    }
+
+    private List<Path> newPathList() {
+        return Arrays.asList(TestConstants.ABS_PATH_A, TestConstants.ABS_PATH_B);
+    }
+
+    @Test
+    public void testAdapt() throws IOException {
+        iterator = IOIteratorAdapter.adapt(newPathList().iterator());
+        assertEquals(TestConstants.ABS_PATH_A, iterator.next());
+    }
+
+    @Test
+    public void testAsIterator() {
+        assertEquals(TestConstants.ABS_PATH_A, iterator.asIterator().next());
+    }
+
+    @Test
+    public void testForEachRemaining() throws IOException {
+        final List<Path> list = new ArrayList<>();
+        iterator.forEachRemaining(p -> list.add(p.toRealPath()));
+        assertFalse(iterator.hasNext());
+        assertEquals(newPathList(), list);
+    }
+
+    @Test
+    public void testHasNext() throws IOException {
+        assertTrue(iterator.hasNext());
+        iterator.forEachRemaining(Path::toRealPath);
+        assertFalse(iterator.hasNext());
+    }
+
+    @Test
+    public void testNext() throws IOException {
+        assertEquals(TestConstants.ABS_PATH_A, iterator.next());
+    }
+
+    @Test
+    public void testRemove() throws IOException {
+        assertThrows(IllegalStateException.class, iterator::remove);
+        iterator.next();
+        assertThrows(UnsupportedOperationException.class, iterator::remove);
+    }
+
+}
diff --git a/src/test/java/org/apache/commons/io/function/IOIteratorTest.java b/src/test/java/org/apache/commons/io/function/IOIteratorTest.java
new file mode 100644
index 00000000..47101ca3
--- /dev/null
+++ b/src/test/java/org/apache/commons/io/function/IOIteratorTest.java
@@ -0,0 +1,94 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.commons.io.function;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+import java.io.IOException;
+import java.nio.file.Path;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Iterator;
+import java.util.List;
+
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+
+/**
+ * Tests {@link IOIterator}.
+ */
+public class IOIteratorTest {
+
+    private IOIterator<Path> iterator;
+
+    @BeforeEach
+    public void beforeEach() {
+        iterator = IOIterator.adapt(newPathList().iterator());
+    }
+
+    private List<Path> newPathList() {
+        return Arrays.asList(TestConstants.ABS_PATH_A, TestConstants.ABS_PATH_B);
+    }
+
+    @Test
+    public void testAdapt() throws IOException {
+        iterator = IOIterator.adapt(newPathList().iterator());
+        assertEquals(TestConstants.ABS_PATH_A, iterator.next());
+    }
+
+    @Test
+    public void testAsIterator() {
+        final Iterator<Path> asIterator = iterator.asIterator();
+        assertTrue(asIterator.hasNext());
+        assertEquals(TestConstants.ABS_PATH_A, asIterator.next());
+        assertThrows(UnsupportedOperationException.class, asIterator::remove);
+    }
+
+    @Test
+    public void testForEachRemaining() throws IOException {
+        final List<Path> list = new ArrayList<>();
+        iterator.forEachRemaining(p -> list.add(p.toRealPath()));
+        assertFalse(iterator.hasNext());
+        assertEquals(newPathList(), list);
+    }
+
+    @Test
+    public void testHasNext() throws IOException {
+        assertTrue(iterator.hasNext());
+        iterator.forEachRemaining(Path::toRealPath);
+        assertFalse(iterator.hasNext());
+    }
+
+    @Test
+    public void testNext() throws IOException {
+        assertEquals(TestConstants.ABS_PATH_A, iterator.next());
+    }
+
+    @Test
+    public void testRemove() throws IOException {
+        assertThrows(IllegalStateException.class, iterator::remove);
+        assertThrows(IllegalStateException.class, iterator::remove);
+        iterator.next();
+        assertThrows(UnsupportedOperationException.class, iterator::remove);
+        assertThrows(UnsupportedOperationException.class, iterator::remove);
+    }
+
+}