69

breakGroovy はandcontinueをクロージャー内からサポートしていないようです。これをシミュレートする最良の方法は何ですか?

revs.eachLine { line -> 
    if (line ==~ /-{28}/) {
         // continue to next line...
    }
}
4

6 に答える 6

72

中断ではなく、きれいに継続することのみをサポートできます。特に eachLine や each のようなものでは。break をサポートできないのは、これらのメソッドがどのように評価されるかに関係しており、メソッドに伝達できるループを終了しないことは考慮されていません。続行をサポートする方法は次のとおりです --

最善のアプローチ (結果の値が必要ないと仮定)。

revs.eachLine { line -> 
    if (line ==~ /-{28}/) {
        return // returns from the closure
    }
}

サンプルが本当に単純な場合、これは読みやすさに優れています。

revs.eachLine { line -> 
    if (!(line ==~ /-{28}/)) {
        // do what you would normally do
    }
}

もう 1 つのオプションは、バイトコード レベルでの通常の continue の動作をシミュレートします。

revs.eachLine { line -> 
    while (true) {
        if (line ==~ /-{28}/) {
            break
        }
        // rest of normal code
        break
    }

}

ブレークをサポートする 1 つの可能な方法は、例外を使用することです。

try {
    revs.eachLine { line -> 
        if (line ==~ /-{28}/) {
            throw new Exception("Break")
        }
    }
} catch (Exception e) { } // just drop the exception

NumberFormatExceptions や IOExceptions など、実際の例外をスローする可能性のある他の処理がそのクラスで行われている場合は特に、カスタム例外タイプを使用して、他の実際の例外をマスクしないようにすることをお勧めします。

于 2008-10-15T18:00:29.003 に答える
17

クロージャーはループ/反復構造ではないため、中断または継続できません。代わりに、反復ロジックを処理/解釈/処理するために使用されるツールです。次のように、処理せずにクロージャーから戻るだけで、特定の反復を無視できます。

revs.eachLine { line -> 
    if (line ==~ /-{28}/) {
            return
    }

}

中断のサポートはクロージャー レベルでは発生しませんが、代わりに、クロージャーを受け入れたメソッド呼び出しのセマンティクスによって暗示されます。つまり、コレクション全体を処理することを目的としたコレクションのようなもので「each」を呼び出す代わりに、特定の条件が満たされるまで処理する find を呼び出す必要があります。ほとんどの場合 (すべて?)、クロージャーから抜け出す必要があると感じる場合、本当にやりたいことは、反復中に特定の条件を見つけて、find メソッドを論理的なニーズだけでなく意図にも一致させることです。悲しいことに、いくつかの API は find メソッドのサポートを欠いています... ファイルなど。言語にブレーク/コンティニューを含めるべきかどうかの議論に費やされたすべての時間が、これらの無視された領域に find メソッドを追加することに十分に費やされた可能性があります。firstDirMatching(Closure c) や findLineMatching(Closure c) のようなものは大いに役立ち、「なぜ抜け出せないのか...?」の 99% 以上に答えます。メーリングリストにポップアップする質問。とはいえ、MetaClass または Categories を介してこれらのメソッドを自分で追加するのは簡単です。

class FileSupport {
   public static String findLineMatching(File f, Closure c) {
      f.withInputStream {
         def r = new BufferedReader(new InputStreamReader(it))
         for(def l = r.readLine(); null!=l; l = r.readLine())
             if(c.call(l)) return l
         return null
      }
   }
}

using(FileSupport) { new File("/home/me/some.txt").findLineMatching { line ==~ /-{28}/ }

例外やその他の魔法を含む他のハックは機能する可能性がありますが、状況によっては余分なオーバーヘッドが発生し、他の状況では可読性が複雑になります。本当の答えは、コードを見て、本当に反復しているのか検索しているのかを尋ねることです。

于 2008-10-18T02:43:04.360 に答える
11

Java で静的な Exception オブジェクトを事前に作成し、クロージャー内から (静的) 例外をスローすると、実行時のコストは最小限になります。実際のコストは、例外をスローするときではなく、例外を作成するときに発生します。Martin Odersky (Scala の発明者) によると、多くの JVM は実際にスロー命令を単一のジャンプに最適化できます。

これは、休憩をシミュレートするために使用できます。

final static BREAK = new Exception();
//...
try {
  ... { throw BREAK; }
} catch (Exception ex) { /* ignored */ }
于 2010-05-24T15:01:53.423 に答える
10

returnを使用して続行クロージャーを使用してbreak します。

ファイルの内容:

1
2
----------------------------
3
4
5

グルーヴィーなコード:

new FileReader('myfile.txt').any { line ->
    if (line =~ /-+/)
        return // continue

    println line

    if (line == "3")
        true // break
}

出力:

1
2
3
于 2013-10-16T21:05:07.077 に答える
4

この場合、おそらくfind()方法を考える必要があります。渡されたクロージャーが最初に true を返した後に停止します。

于 2012-03-27T01:59:06.077 に答える
2

rx-javaを使用すると、イテラブルをオブザーバブルに変換できます。

次に、continueフィルターに置き換え、 takeWhile中断することができます

次に例を示します。

import rx.Observable

Observable.from(1..100000000000000000)
          .filter { it % 2 != 1} 
          .takeWhile { it<10 } 
          .forEach {println it}
于 2015-06-02T09:39:41.297 に答える