简体   繁体   中英

Java : How to pass collection to chainedIterator(Collection<Iterator<? extends E>> iterators) from Apache commons collection4 lib?

I have below code where trying to use chainedIterator(Collection<Iterator<? extends E>> iterators) from org.apache.commons.collections4.IteratorUtils (Apache commons collection4 lib) but giving compile time error.

Here is my code..

private Iterator<Resource> getResources() {
        String[] paths = getParameterValues();
        Collection<Iterator<Resource>> its = new ArrayList<Iterator<Resource>>();       
        for (int i = 0; i < paths.length; i++) {
            String path = paths[i];         
            its.add(getOnlyResource(path));
        }
        return IteratorUtils.chainedIterator(its); //gives compile error - The method chainedIterator(Iterator<? extends E>...) in the type IteratorUtils is not applicable for the arguments (Collection<Iterator<Resource>>)
    }

The problem is the method signature

public static <E> Iterator<E>
    chainedIterator(Collection<Iterator<? extends E>> iterators)

which is too restrictive.

It says that to return an Iterator<Resource> you have to pass in a Collection<Iterator<? extends Resource>> Collection<Iterator<? extends Resource>> .

The method signature reflecting the actual intention has to be

public static <E> Iterator<E>
    chainedIterator(Collection<? extends Iterator<? extends E>> iterators)

Then, your code would compile without error and it can be shown that implementing the method with that relaxed signature is possible, eg

public static <E> Iterator<E>
    chainedIterator(Collection<? extends Iterator<? extends E>> iterators) {

    if(iterators.isEmpty()) return Collections.emptyIterator();
    return iterators.stream()
        .flatMap(it -> StreamSupport.stream(
            Spliterators.<E>spliteratorUnknownSize(it, Spliterator.ORDERED), false))
        .iterator();
}

See also How to convert an iterator to a stream?


But you can work-around the problem of the current method signature by providing exactly what it demands. Just change the declaration

Collection<Iterator<Resource>> its = new ArrayList<Iterator<Resource>>();

to

Collection<Iterator<? extends Resource>> its = new ArrayList<>();

Then, you can use the IteratorUtils as-is. But mind that you don't need a 3rd party library at all. The entire method can be implemented using built-in features only like

private Iterator<Resource> getResources() {
    return Arrays.stream(getParameterValues())
        .map(path -> getOnlyResource(path))
        .flatMap(it -> StreamSupport.stream(
            Spliterators.spliteratorUnknownSize(it, Spliterator.ORDERED), false))
        .iterator();
}

This is similar to the example chainedIterator implementation above, but does not require the step of first collecting the iterators into a collection. Instead, it's lazy, so if the caller doesn't iterate over all elements, this solution might even skip unnecessary getOnlyResource calls.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM