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

daim pushed a commit to branch trunk
in repository https://gitbox.apache.org/repos/asf/jackrabbit-oak.git


The following commit(s) were added to refs/heads/trunk by this push:
     new 7bda86b8dc OAK-11674 : added Iterators.filter replacement in 
oak-commons (#2245)
7bda86b8dc is described below

commit 7bda86b8dc417ea6631759b901d904e34df281a7
Author: Rishabh Kumar <rishabhdaim1...@gmail.com>
AuthorDate: Thu Apr 24 15:58:14 2025 +0530

    OAK-11674 : added Iterators.filter replacement in oak-commons (#2245)
    
    Co-authored-by: Rishabh Kumar <d...@adobe.com>
---
 .../oak/commons/collections/IteratorUtils.java     |  30 ++++++
 .../oak/commons/collections/IteratorUtilsTest.java | 114 +++++++++++++++++++++
 2 files changed, 144 insertions(+)

diff --git 
a/oak-commons/src/main/java/org/apache/jackrabbit/oak/commons/collections/IteratorUtils.java
 
b/oak-commons/src/main/java/org/apache/jackrabbit/oak/commons/collections/IteratorUtils.java
index b48e109a61..6d7d62fccf 100644
--- 
a/oak-commons/src/main/java/org/apache/jackrabbit/oak/commons/collections/IteratorUtils.java
+++ 
b/oak-commons/src/main/java/org/apache/jackrabbit/oak/commons/collections/IteratorUtils.java
@@ -30,6 +30,7 @@ import java.util.NoSuchElementException;
 import java.util.Objects;
 import java.util.PriorityQueue;
 import java.util.Queue;
+import java.util.function.Predicate;
 
 /**
  * Utility methods for {@link Iterator} conversions.
@@ -369,4 +370,33 @@ public class IteratorUtils {
         iterators.forEachRemaining(eIteratorChain::addIterator);
         return eIteratorChain;
     }
+
+    /**
+     * Returns an iterator containing only the elements that match the given 
predicate.
+     * <p>
+     * This method creates a new iterator that will iterate through elements 
from the
+     * source iterator but only return elements that satisfy the specified 
predicate.
+     * The filtering occurs during iteration and the method doesn't consume 
the source iterator
+     * until the returned iterator is advanced.
+     * <p>
+     * Example usage:
+     * <pre>
+     * Iterator&lt;Integer&gt; numbers = Arrays.asList(1, 2, 3, 4, 
5).iterator();
+     * Predicate&lt;Integer&gt; isEven = n -> n % 2 == 0;
+     * Iterator&lt;Integer&gt; evenNumbers = IteratorUtils.filter(numbers, 
isEven);
+     * // evenNumbers will iterate through 2, 4
+     * </pre>
+     * <p>
+     * The returned iterator supports {@link Iterator#remove()} if the source 
iterator supports it.
+     *
+     * @param <T> the type of objects in the iterator
+     * @param itr the source iterator, must not be null
+     * @param predicate the predicate to apply to each element, must not be 
null
+     * @return a filtered iterator
+     * @throws NullPointerException if either the iterator or predicate is null
+     */
+    public static <T> Iterator<T> filter(final Iterator<? extends T> itr, 
final Predicate<? super T> predicate) {
+        return 
org.apache.commons.collections4.IteratorUtils.filteredIterator(itr, 
predicate::test);
+    }
 }
+
diff --git 
a/oak-commons/src/test/java/org/apache/jackrabbit/oak/commons/collections/IteratorUtilsTest.java
 
b/oak-commons/src/test/java/org/apache/jackrabbit/oak/commons/collections/IteratorUtilsTest.java
index 47a4393823..faa04276ec 100644
--- 
a/oak-commons/src/test/java/org/apache/jackrabbit/oak/commons/collections/IteratorUtilsTest.java
+++ 
b/oak-commons/src/test/java/org/apache/jackrabbit/oak/commons/collections/IteratorUtilsTest.java
@@ -817,4 +817,118 @@ public class IteratorUtilsTest {
 
         Assert.assertThrows(NullPointerException.class, () -> 
IteratorUtils.chainedIterator(new ArrayList<>(Arrays.asList(iterator1, 
iterator2, null)).iterator()));
     }
+
+    @Test
+    public void testFilterWithMatchingElements() {
+        List<Integer> list = Arrays.asList(1, 2, 3, 4, 5);
+        Iterator<Integer> filtered = IteratorUtils.filter(list.iterator(), n 
-> n % 2 == 0);
+
+        List<Integer> result = new ArrayList<>();
+        filtered.forEachRemaining(result::add);
+
+        Assert.assertEquals(Arrays.asList(2, 4), result);
+    }
+
+    @Test
+    public void testFilterWithNoMatchingElements() {
+        List<String> list = Arrays.asList("apple", "banana", "cherry");
+        Iterator<String> filtered = IteratorUtils.filter(list.iterator(), s -> 
s.startsWith("d"));
+
+        Assert.assertFalse(filtered.hasNext());
+    }
+
+    @Test
+    public void testFilterWithAllMatchingElements() {
+        List<Integer> list = Arrays.asList(10, 20, 30, 40);
+        Iterator<Integer> filtered = IteratorUtils.filter(list.iterator(), n 
-> n > 0);
+
+        List<Integer> result = new ArrayList<>();
+        filtered.forEachRemaining(result::add);
+
+        Assert.assertEquals(list, result);
+    }
+
+    @Test
+    public void testFilterWithEmptyIterator() {
+        Iterator<String> emptyIterator = Collections.emptyIterator();
+        Iterator<String> filtered = IteratorUtils.filter(emptyIterator, s -> 
true);
+
+        Assert.assertFalse(filtered.hasNext());
+    }
+
+    @Test
+    public void testFilterWithNullIterator() {
+        Assert.assertThrows(NullPointerException.class, () -> 
IteratorUtils.filter(null, item -> true));
+    }
+
+    @Test
+    public void testFilterWithNullPredicate() {
+        Iterator<String> iterator = Arrays.asList("a", "b").iterator();
+        Assert.assertThrows(NullPointerException.class, () -> 
IteratorUtils.filter(iterator, null));
+    }
+
+    @Test
+    public void testFilterWithRemove() {
+        List<String> list = new ArrayList<>(Arrays.asList("keep", "remove", 
"keep"));
+        Iterator<String> filtered = IteratorUtils.filter(list.iterator(), 
"keep"::equals);
+
+        // First element matches
+        Assert.assertTrue(filtered.hasNext());
+        Assert.assertEquals("keep", filtered.next());
+        filtered.remove();
+
+        // Skip "remove" as it doesn't match
+        Assert.assertTrue(filtered.hasNext());
+        Assert.assertEquals("keep", filtered.next());
+
+        Assert.assertEquals(Arrays.asList("remove", "keep"), list);
+    }
+
+    @Test
+    public void testFilterWithNullElements() {
+        List<String> list = Arrays.asList("a", null, "b", null, "c");
+        Iterator<String> filtered = IteratorUtils.filter(list.iterator(), 
Objects::isNull);
+
+        List<String> result = new ArrayList<>();
+        filtered.forEachRemaining(result::add);
+
+        Assert.assertEquals(Arrays.asList(null, null), result);
+    }
+
+    @Test
+    public void testFilterWithCustomObjects() {
+        class Person {
+            private final String name;
+            private final int age;
+
+            Person(String name, int age) {
+                this.name = name;
+                this.age = age;
+            }
+
+            public int getAge() {
+                return age;
+            }
+
+            @Override
+            public String toString() {
+                return name;
+            }
+        }
+
+        List<Person> people = Arrays.asList(
+                new Person("Alice", 25),
+                new Person("Bob", 17),
+                new Person("Charlie", 30),
+                new Person("David", 16)
+        );
+
+        // Filter adults (age >= 18)
+        Iterator<Person> adults = IteratorUtils.filter(people.iterator(), p -> 
p.getAge() >= 18);
+
+        List<String> adultNames = new ArrayList<>();
+        adults.forEachRemaining(p -> adultNames.add(p.toString()));
+
+        Assert.assertEquals(Arrays.asList("Alice", "Charlie"), adultNames);
+    }
 }

Reply via email to