java – Is there a concise way to iterate over an indexed stream in Java 8?

If you don’t mind using a third party library, Eclipse Collections has zipWithIndex And forEachWithIndex available for use on many types. Here are a number of solutions to this challenge for both the JDK types and the Eclipse collection types they use zipWithIndex.

String[] names = { "Sam", "Pamela", "Dave", "Pascal", "Erik" };
ImmutableList expected = Lists.immutable.with("Erik");
Predicate> predicate =
    pair -> pair.getOne().length() <= pair.getTwo() + 1;

// JDK Types
List strings1 = ArrayIterate.zipWithIndex(names)
    .collectIf(predicate, Pair::getOne);
Assert.assertEquals(expected, strings1);

List list = Arrays.asList(names);
List strings2 = ListAdapter.adapt(list)
    .zipWithIndex()
    .collectIf(predicate, Pair::getOne);
Assert.assertEquals(expected, strings2);

// Eclipse Collections types
MutableList mutableNames = Lists.mutable.with(names);
MutableList strings3 = mutableNames.zipWithIndex()
    .collectIf(predicate, Pair::getOne);
Assert.assertEquals(expected, strings3);

ImmutableList immutableNames = Lists.immutable.with(names);
ImmutableList strings4 = immutableNames.zipWithIndex()
    .collectIf(predicate, Pair::getOne);
Assert.assertEquals(expected, strings4);

MutableList strings5 = mutableNames.asLazy()
    .zipWithIndex()
    .collectIf(predicate, Pair::getOne, Lists.mutable.empty());
Assert.assertEquals(expected, strings5);

Here is a solution using forEachWithIndex instead.

MutableList mutableNames =
    Lists.mutable.with("Sam", "Pamela", "Dave", "Pascal", "Erik");
ImmutableList expected = Lists.immutable.with("Erik");

List actual = Lists.mutable.empty();
mutableNames.forEachWithIndex((name, index) -> {
        if (name.length() <= index + 1)
            actual.add(name);
    });
Assert.assertEquals(expected, actual);

If you change the lambdas to anonymous inner classes above, then all of these code examples will work in Java 5 – 7 as well.

Note: I’m a committer for Eclipse collections

Leave a comment