2016-11-16 16 views
1

次のことが可能かどうかわかりません。私は、すなわちJavaで再帰ラムダ関数を実装する

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

が、このことも可能のようなものです、Runnable自身を含むようにRunnablerun()方法をご希望ですか?もしそうなら、どうですか? (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

最も簡単な方法は、ラムダの内容をメソッドに入れ、メソッドリファレンスを使用して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

短い答え:

長い答え: あなたのコードはあなたに構文エラーを与えます。どうして?ラムダ内で使用されるexecuteAfterは初期化されません。それはラムダ定義の全体の後でのみ初期化されます。

たとえば、次の例を考えます。

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

あなたのケースは似ています。ラムダの内部では、executeAfterは初期化されていません。上で述べたように、ラムダ定義の全体の後でのみ初期化されます。

さらにノードに1つのことは、ラムダの内部で使用されるためには変数reconnectsが最終でなければならないということです。それが最後の変数であれば、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); 
    } 
};