Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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.

like image 971
uzilan Avatar asked Dec 25 '22 00:12

uzilan


2 Answers

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();
})));
like image 100
Holger Avatar answered Dec 28 '22 07:12

Holger


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.

like image 39
Eran Avatar answered Dec 28 '22 08:12

Eran