HiveBrain v1.2.0
Get Started
← Back to all entries
patternjavaMinor

CombinedIterable for Java

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
combinediterableforjava

Problem

This class combines multiple instances of Iterable into one and iterates through them in the order they are given to CombinedIterable.

CombinedIterable.java:

```
package net.coderodde.util;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.NoSuchElementException;
import java.util.Set;

/**
* This class implements an {@code Iterable} combining multiple
* {@code Iterable}s into one.
*
* @author Rodion "rodde" Efremov
* @version 1.6 (Feb 11, 2016)
* @param the actual type of elements being iterated.
*/
public class CombinedIterable implements Iterable {

private final Iterator[] iterators;

public static Iterable combine(Iterable... iterables) {
return new CombinedIterable(iterables);
}

private CombinedIterable(Iterable... iterables) {
this.iterators = new Iterator[iterables.length];

for (int i = 0; i iterator() {
return new MultiIterator();
}

private final class MultiIterator implements Iterator {

private int index;
private Iterator lastReadIterator;

MultiIterator() {
if (iterators.length > 0) {
this.lastReadIterator = (Iterator) iterators[0];
}
}

@Override
public boolean hasNext() {
while (index ) iterators[index];
T element = lastReadIterator.next();

if (!iterators[index].hasNext()) {
++index;
}

return element;
}

@Override
public void remove() {
lastReadIterator.remove();
}
}

public static void main(String[] args) {
List list1 = new ArrayList<>();
List list2 = new LinkedList<>();
Set set = new LinkedHashSet<>();

for (int i = 10; i emptySet = Collections.emptySet();
List emptyList = Collectio

Solution

Your code has a lot of warnings that can be avoided.

-
You should never use raw types, like in the following

return new CombinedIterable(iterables); // use CombinedIterable<> instead


and

return new MultiIterator(); // use MultiIterator<> instead


-
You should not create array of a generic type but prefer to use a List.

this.iterators = new Iterator[iterables.length];


This is fragile and leads to a lot of unnecessary warnings in your code, because you need to explicitely cast afterwards, like in:

lastReadIterator = (Iterator) iterators[index];


Instead, what you want is to declare iterators as a List>. This way, you can use an enhanced for loop to loop through the iterable to add each of their iterator to the list.

private final List> iterators;

private CombinedIterable(Iterable... iterables) {
    this.iterators = new ArrayList<>(iterables.length);
    for (Iterable iterable : iterables) {
        this.iterators.add(iterable.iterator());
    }
}


also you can retrieve an iterator from that list with just

lastReadIterator = iterators.get(index);


-
The type T of MultiIterator is hiding the type T of CombinedIterable. Since MultiIterator is an internal helper class, it actually does not need to be typed: it can reuse the type of the enclosing CombinedIterable, with:

private final class MultiIterator implements Iterator { /* ... */ }


-
The method combine and the constructor CombinedIterable both take a vararg of a generic type, which leads a warning because of a potential heap pollution. If you know this won't happen, you can annotate the method with @SafeVarargs and remove the warning. It also documents that the method does not perform potentially unsafe operation on the varargs parameter.

A side-note in your next() method: the following block of code

if (!iterators.get(index).hasNext()) {
    ++index;
}


is not necessary since the method hasNext() will have already set the index to the next iterator to read from. As such, you can safely remove it.

Code Snippets

return new CombinedIterable(iterables); // use CombinedIterable<> instead
return new MultiIterator(); // use MultiIterator<> instead
this.iterators = new Iterator[iterables.length];
lastReadIterator = (Iterator<T>) iterators[index];
private final List<Iterator<T>> iterators;

private CombinedIterable(Iterable<T>... iterables) {
    this.iterators = new ArrayList<>(iterables.length);
    for (Iterable<T> iterable : iterables) {
        this.iterators.add(iterable.iterator());
    }
}

Context

StackExchange Code Review Q#119622, answer score: 4

Revisions (0)

No revisions yet.