1

I don't know if the following thing is possible. I would like a Runnable's run() method to contain the Runnable itself, i.e.

reconnects = 3;
Runnable executeAfter = () -> {
    if ( --reconnects < 0 ) {
        println("%nStop using port %d.", this.port);
        //...
    } else { // try to reconnect
        println("%nReconnecting...");
        cmdRun = new CmdRun(command, executeAfter);
        (new Thread(cmdRun)).start();
        //...
    }
};

Is something like this even possible? If so, how? (CmdRun's constructor is CmdRun(String command, Runnable executeAfter))

5 Answers 5

2

Is lambda a must here? If not, switching to older equivalent syntax should be simple:

An example:

public class TestLambda {
    static int count = 0;
    public static void main(String[] args) {
        // lambda not going to work
        //Runnable foo = () -> { if (count < 5) { call(foo); } };
        // nor
        //Runnable foo = () -> { if (count < 5) { call(this); } };

        // using old way of anonymous inner class will work
        Runnable foo = new Runnable() {
            @Override public void run() {
                if (count < 5) {
                    call(this);
                }
            }
        };

        foo.run();
    }

    public static void call(Runnable action) {
        count++;
        System.out.println("in call " + count);
        action.run();
    }
}
Sign up to request clarification or add additional context in comments.

1 Comment

although it works, but doing something like retry/reconnect etc recursively, and spawning new thread in each level of recursion seems to be error prone. Consider changing the design
1

The easiest way is probably to put the content of your lambda in a method and use a method reference to define your Runnable.

Comments

1

The Runnable's run() can not contain a self reference as its illegal. Im not exactly sure what you are trying to achieve but something like this should work :

class CmdRun implements Runnable {

    final Object command;
    final Runnable runnable;

    final Runnable executeAfter = () -> {
        if ( --reconnects < 0 ) {
            System.out.println("%nStop using port %d." + port);
            //...
        } else { // try to reconnect
            System.out.println("%nReconnecting...");
            CmdRun cmdRun = new CmdRun(command);
            (new Thread(cmdRun)).start();
            //...
        }
    };

    public CmdRun(Object command) {
        this.command = command;
        this.runnable = executeAfter;
    }

    @Override
    public void run() {
        runnable.run();
    }
}

Comments

1

Short answer: No.

Long answer: Your code will give you a syntax error. Why? The executeAfter used inside the lambda is not initialized; it is only initialized after the full body of the lambda definition.

For example, consider the below example.

int i;
sum(i, 5); // Syntax error!! Variable i is not initialized...

Your case is similar. Inside the lambda, executeAfter is not initialized. As stated above, it is only initialized after the full body of the lambda's definition.

One additional thing to node is that the variable reconnects must be a final in order to be used inside the lambda. If it is a final variable, then you cannot use the -- operator on it inside your if condition.

Comments

1

Actually if you don't mind to introduce a new interface (or if you require such functionality more often), you could use the following:

@FunctionalInterface
interface RecursiveRunnable extends Runnable {
    default void run() {
        run(this);
    }
    public void run(RecursiveRunnable runnable);
}

This will now allow you to recursively call the runnable, e.g.:

int maxTries = 3;
AtomicInteger counter = new AtomicInteger();
RecursiveRunnable foo = runnable -> {
    if (counter.getAndIncrement() < maxTries) {
        println("Reconnecting... %n");
        runnable.run(); // same as: runnable.run(runnable)
    } else {
        println("Stop using port %d%n", port);
    }
};

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.