1

I have a list of runnables that I would like to call using lambda expressions:

Arrays.asList(runnable1, runnable2, runnable3, ...).forEach(r->r.run());

Is there a 'better' (more efficient) shortcut to call the Runnables run() method other than the following way?

Arrays.asList(runnable1, runnable2, runnable3, ...).forEach(Runnable::run);

I think this expression will be translated to a Runnable wrapping the runnable instance in the list.

EDIT: My assumption/concern (maybe wrong) is that the compiler will translate the expression list.forEach(Runnable::run) to something like this, and thus not 'efficient':

list.forEach(r -> new Runnable() {

        @Override
        public void run() {
            r.run();
        }
    });
erdal.karaca
  • 693
  • 1
  • 4
  • 20
  • 4
    There is no wrapping here. You already have instances of ``Runnable``, each of them has the ``run`` method invoked. But this happens sequentially, not in parallel (which you might expect because ``Runnable``s often show up in conjunction with threads). – f1sh Jul 24 '18 at 08:28
  • 1
    No, it's a statement (note that `List.forEach` is `void`). – Andy Turner Jul 24 '18 at 08:28
  • 2
    "Efficient" in what sense? –  Jul 24 '18 at 08:28
  • 1
    After your edit: No, it doesn't. The ``Runnable`` is not wrapped, ``run`` is called on your original instances. Your first two snippets are effectively the same. – f1sh Jul 24 '18 at 08:36
  • 2
    Why should *new* `Runnable`s be created? Those already exist, their method `run` will be called. –  Jul 24 '18 at 08:36
  • 3
    @erdal.karaca Runnable::run is just a shorter version for calling the run method of a Runnable interface. It will not be wrapped, why would it be wrapped? – LoolKovsky Jul 24 '18 at 08:37
  • 1
    @erdal.karaca Anyway, you might think of using a parallel stream if it suits your needs: `Stream.of(arrayOfRunnables).parallel().forEach(Runnable:run);` More details about when to use a pallel stream can be found here: [Should i always use a parallel stream when possible?](https://stackoverflow.com/questions/20375176/should-i-always-use-a-parallel-stream-when-possible) – LoolKovsky Jul 24 '18 at 08:47
  • Thanks, guys, for the comments: My question was based on wrong assumptions. Will close the question as invalid. Or if you can answer with a link to the lang specs I can read to get more clarification, I will accept it. – erdal.karaca Jul 24 '18 at 08:53
  • @erdal.karaca If you are facing performance issues, and that is the reason why you were asking this question, my other comment could help you. – LoolKovsky Jul 24 '18 at 08:56
  • @TothLudovicAndreas: just wanted know if the compiler would create redundant wrapping objects when using a method pointer – erdal.karaca Jul 24 '18 at 08:59

1 Answers1

1

Whether you write

Arrays.asList(runnable1, runnable2, runnable3, ...).forEach(r->r.run());

or

Arrays.asList(runnable1, runnable2, runnable3, ...).forEach(Runnable::run);

in either case, there will be an instance of Consumer generated, as that’s what Iterable.forEach expects.

The consumer will be equivalent to

Arrays.asList(runnable1, runnable2, runnable3, ...).forEach(new Consumer<Runnable>() {
    public void accept(Runnable r) {
        r.run();
    }
});

but that’s not a wrapper around a runnable, as it encapsulates an action applied to arbitrary Runnable instances passed in as parameter. Hence, there is at most one Consumer instance created for the entire forEach operation.

As explained in this answer, the JVM will be responsible for the creation of the Consumer instance and has the freedom to reuse existing instances, which happens in practice with the current implementation and non-capturing instances of functional interfaces, which applies to both variants, using a lambda expression or a method reference, so there will be only one Consumer instance, reused even on subsequent evaluations of the statement.

The only difference with current compilers is that the lambda expression r->r.run() will generate a method within your class calling the run() method whereas for the method reference, the runtime generated Consumer implementation class will call it directly, which makes the method reference more efficient on the hard-to-ever-measure scale.

Holger
  • 285,553
  • 42
  • 434
  • 765