uzilan
uzilan

Reputation: 2624

How to create nice iterations in Java 8

Inspired by Adam Bien's weblog I wanted to replace a common iteration in Java 7 into a nicer one in Java 8. The older code looked like this:

void repeatUsingJava7(int times) {
    for (int i = 0; i < times; i++) {
        doStuff();
        doMoreStuff();
        doEvenMoreStuff();
    }
}

...which is not too nice. So I replaced it using Adam Bein's example into this:

void repeatUsingJava8(int times) {
    IntStream.range(0, times).forEach(
        i -> {
            doStuff();
            doMoreStuff();
            doEvenMoreStuff();
        }
    );
}

...which is a step in the right direction, but does not make the code much simpler to read, and also introduces an unneeded variable i, as well as an extra pair of curly brackets. So now I'm wondering if there are other ways to write this code which will make it even nicer and easier to read, primarily using Java 8.

Upvotes: 4

Views: 715

Answers (4)

Tomasz Waszczyk
Tomasz Waszczyk

Reputation: 3169

You can also use from predicates:

IntStream.range(0, 10).sorted().filter(i -> i > 5).forEach(System.out::println);

sorted and filer is additional .

Upvotes: 0

Stuart Marks
Stuart Marks

Reputation: 132530

As others have pointed out, replacing a simple for-loop with a stream isn't necessarily any better, for this one specific example. However, advantages start to appear if the problem you're trying to solve is more general. For example, instead of repeating some specific code n times, suppose you need to repeat some piece of code that's passed as a parameter? Consider:

void repeat(int count, Runnable action) {
    IntStream.range(0, count).forEach(i -> action.run());
}

Now you can write,

repeat(3, () -> System.out.println("Hello!"));

or perhaps

repeat(4, this::doStuff);

Maybe instead performing a single action n times, you want to perform multiple actions n times. You could do something like this:

void repeat(int count, Runnable... actions) {
    IntStream.range(0, count).forEach(i -> Arrays.asList(actions).forEach(Runnable::run));
}

Then you'd be able to write:

repeat(5, this::doStuff, this::doMoreStuff, this::doEvenMoreStuff);

The repeat implementation is somewhat more concise (perhaps terse) than the conventional Java 7 way:

void repeatOldWay(int count, Runnable...actions) {
    for (int i = 0; i < count; i++) {
        for (Runnable r : actions) {
            r.run();
        }
    }
}

The real advantage comes at the call site, where you can simply pass in a count and one or more lambda expressions or method references, instead of replicating the nested for-loop logic.

Upvotes: 1

Holger
Holger

Reputation: 298519

Just for completeness, here is a solution which doesn’t need the counter variable:

void repeatUsingJava8(int times) {
    Collections.<Runnable>nCopies(times, ()->{
        doStuff();
        doMoreStuff();
        doEvenMoreStuff();
    }).forEach(Runnable::run);
}

It would become more readable if there is only one method to be invoked multiple times as in that case it could be written as, e.g.

void repeatUsingJava8(int times) {
    Collections.<Runnable>nCopies(times, this::doStuff).forEach(Runnable::run);
}

If it has to be Streams, the code above is equivalent to

void repeatUsingJava8(int times) {
    Stream.<Runnable>generate(()->this::doStuff).limit(times).forEach(Runnable::run);
}

However, these alternatives are not really better than the good old for loop. If you consider parallel execution, which is a real advantage of Streams over ordinary for loops, there are still alternatives based on commonly known, approved APIs:

ExecutorService es=Executors.newCachedThreadPool();
es.invokeAll(Collections.nCopies(times, Executors.callable(()->{
    doStuff();
    doMoreStuff();
    doEvenMoreStuff();
})));

Upvotes: 5

Eran
Eran

Reputation: 394016

I don't see any advantage in using Streams for this case. Streams are useful for processing of Collections, arrays and other data structures that contain multiple elements of the same type.

Here you are not processing any data, you just repeat the same action multiple times. There is no reason to replace the good old for loop for that purpose.

Upvotes: 4

Related Questions