0

I have a Runnable task (doSomething) that I need to parametrise depending on who calls run().

    Class SomeClass {
    
        Public void foo(ScheduledExecutorService execService, ){
            ...
            Runnable doSomething = () -> {
                /*Code that I DON’T want to duplicate*/
                ...
                /* small piece of code that I need to parametrise */
            };
            ...
        
            // after someDelayInSeconds doSomething.run() will be called
            execService.schedule(doSomething, someDelayInSeconds, TimeUnit.SECONDS); 

            // this might or might not call doSomething.run()
            bar(doSomething); 
    
            ...
        
        }

        private void bar(Runnable doSomething){

           ...
           if(/* some conditions are met */)
              doSomething.run();
           ...
        }
    }

So far the only alternative I have is to transform the anonymous class into a named class and create two objects with the required parameters.

Would there be a more elegant way?

Manolo
  • 1,500
  • 1
  • 11
  • 15

2 Answers2

1

I'm not sure, if this is what you are looking for:

  // provide config 
  Map<String, String> config = new HashMap<>();
  config.put( "someKey", "someValue" );

  Consumer<Map<String, String>> consumer = cfg -> {
     Runnable doSth = () -> {
        if ( cfg.get( "someKey" ).equals( "someValue" ) ) {

        }
     };
     doSth.run();
  };

  // apply different configurations depending on your needs
  consumer.accept( config );
Tavark
  • 29
  • 2
1

I suggest you change doSomething to a Consumer that accepts your parameters:

public void foo(ScheduledExecutorService execService) {
    Consumer<YourParams> doSomething = (params) -> {
        /*Code that I DON’T want to duplicate*/
        /* small piece of code that I need to parametrise */
        // use params
    };

    // after someDelayInSeconds doSomething.run() will be called
    YourParams asyncParams = /* parameters for async execution */;
    execService.schedule(() -> doSomething.accept(asyncParams), someDelayInSeconds, TimeUnit.SECONDS);

    // this might or might not call doSomething.run()
    bar(doSomething);

}

private void bar(Consumer<YourParams> doSomething) {
    if (/* some conditions are met */) {doSomething.accept(otherParams);}
}

In the scheduled execution you then transform doSomething into a Runnable by passing the default parameters for asynchronous execution, while in bar() you pass the alternative parameters of your choice directly.

marc_s
  • 732,580
  • 175
  • 1,330
  • 1,459
Didier L
  • 18,905
  • 10
  • 61
  • 103
  • This helped thanks! I ended-up using a BiConsumer as I had two parameters. In the case of N parameters the answer from @tavark gives a good hint. Alternatively something like this can be used: https://stackoverflow.com/a/19649473/2022175 – Manolo Feb 24 '22 at 12:26
  • If you have N parameters you can always wrap them in a parameter object, or indeed implement a custom functional interface. – Didier L Feb 24 '22 at 12:30