2016-11-16 175 views
1

我不知道下列事情是否可能。我想一個Runnablerun()方法包含Runnable本身,即在Java中實現遞歸lambda函數

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)

回答

2

拉姆達必須在這裏嗎?如果不是,切換到舊的等效語法應該是簡單的:

一個例子:

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

這工作。非常感謝你。 – dotwin

+0

儘管它有效,但是像遞歸地執行重試/重新連接等操作,並且在遞歸的每個級別中產生新的線程似乎都是錯誤的。考慮改變設計 –

1

最簡單的方法可能是將lambda的內容放入方法中,並使用方法引用來定義Runnable。

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

簡短的回答:

龍答: 您的代碼會給你一個語法錯誤。爲什麼? lambda中使用的executeAfter未初始化;它只是在完整的lambda定義之後進行初始化。

例如,考慮下面的例子。

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

您的情況類似。在lambda內部,executeAfter未初始化。如上所述,它僅在lambda定義的完整主體之後進行初始化。

節點的另外一件事是變量reconnects必須是最後才能在lambda內部使用。如果它是最後一個變量,那麼在if條件中不能使用它的--運算符。

1

其實,如果你不介意引入一個新的界面(或者,如果你更經常需要這樣的功能),你可以使用下列內容:

@FunctionalInterface 
interface RecursiveRunnable extends Runnable { 
    default void run() { 
     run(this); 
    } 
    public void run(RecursiveRunnable 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); 
    } 
};