在Java中实现递归lambda函数

时间:2016-11-16 05:20:51

标签: java recursion lambda

我不知道以下事情是否可行。我希望Runnable run()方法包含Runnable本身,即

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();
        //...
    }
};

这样的事情是否可能?如果是这样,怎么样? (CmdRun的构造函数为CmdRun(String command, Runnable executeAfter)

5 个答案:

答案 0 :(得分:2)

lambda必须在这吗?如果没有,切换到较旧的等效语法应该很简单:

一个例子:

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();
    }
}

答案 1 :(得分:1)

最简单的方法可能是将lambda的内容放在方法中,并使用方法引用来定义Runnable。

答案 2 :(得分:1)

Runnable的run()不能包含自我引用,因为它是非法的。 我不完全确定你想要实现的目标,但这样的事情应该有效:

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();
    }
}

答案 3 :(得分:1)

简答:否。

答案很长: 您的代码会给您一个语法错误。为什么? lambda中使用的executeAfter未初始化;它仅在lambda定义的完整主体之后初始化。

例如,请考虑以下示例。

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

你的情况类似。在lambda中,executeAfter未初始化。如上所述,它仅在lambda定义的完整主体之后初始化。

节点的另一个要点是变量reconnects必须是final才能在lambda中使用。如果它是最终变量,那么您不能在if条件中使用--运算符。

答案 4 :(得分:1)

实际上,如果您不介意引入新界面(或者如果您经常需要此类功能),可以使用以下内容:

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

现在允许您以递归方式调用runnable,例如:

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);
    }
};