Le meilleur modèle pour simuler "continuer" dans la fermeture Groovy

il semble que Groovy ne supporte pas break et continue de l'intérieur d'une fermeture. Quelle est la meilleure façon de simuler cela?

revs.eachLine { line -> 
    if (line ==~ /-{28}/) {
         // continue to next line...
    }
}
66
demandé sur Opal 2008-10-15 21:32:55

6 réponses

vous pouvez seulement soutenir continuer proprement, pas casser. Surtout avec des trucs comme chaque ligne et chaque. L'incapacité à supporter la rupture doit être liée à la façon dont ces méthodes sont évaluées, il n'y a aucune considération prise pour ne pas finir la boucle qui peut être communiquée à la méthode.

meilleure approche (en supposant que vous n'avez pas besoin de la valeur résultante).

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

Si votre échantillon est vraiment simple, ce est bon pour des raisons de lisibilité.

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

une autre option, simule ce qu'un continue ferait normalement au niveau du bytecode.

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

}

l'une des façons possibles de supporter le break est par le biais d'exceptions:

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

vous pouvez utiliser un type d'exception personnalisé pour éviter de masquer d'autres exceptions réelles, surtout si vous avez d'autres traitements en cours dans cette classe qui pourraient jeter des exceptions réelles, comme NumberFormatExceptions ou IOExceptions.

71
répondu shemnon 2008-10-15 18:00:29
Les fermetures

ne peuvent pas se briser ou continuer parce qu'elles ne sont pas des constructions en boucle/itération. Ce sont plutôt des outils utilisés pour traiter/interpréter/gérer la logique itérative. Vous pouvez ignorer des itérations données en revenant simplement de la fermeture sans traitement comme dans:

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

}

Saut de soutien n'est pas au niveau de la fermeture, mais est plutôt implicite par la sémantique de l'appel de la méthode accepté la fermeture. En bref, cela signifie qu'au lieu d'appeler "chacun" sur quelque chose comme une collection qui est destiné à traiter l'ensemble de la collection, vous devez appeler trouver qui traitera jusqu'à ce qu'une certaine condition est respectée. La plupart (toutes? ce que vous voulez vraiment faire est de trouver une condition spécifique au cours de votre itération qui rend la méthode find compatible non seulement avec vos besoins logiques mais aussi avec votre intention. Malheureusement, certaines API manquent de support pour une méthode find... Fichier par exemple. Il est possible que tout le temps passé à discuter la langue devrait inclure la pause/continuer aurait pu être bien dépensée en ajoutant la méthode find à ces domaines négligés. Quelque chose comme la premièrematching(fermeture c) ou findLineMatching(Fermeture c) irait loin et répondre à 99+% de la "Pourquoi ne puis-je pas rompre...?"des questions qui apparaissent dans les listes de diffusion. Cela dit, il est trivial d'ajouter ces méthodes vous-même via MetaClass ou catégories.

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}/ }

D'autres piratages impliquant des exceptions et d'autres magies peuvent fonctionner mais introduire des frais généraux supplémentaires dans certaines situations et altérer la lisibilité dans d'autres. La vraie réponse est de regarder votre code et de demander si vous êtes vraiment itératif ou de recherche à la place.

15
répondu Cliff 2008-10-18 02:43:04

si vous pré-créez un objet D'Exception statique en Java, puis lancez l'exception (statique) à partir d'une fermeture, le coût d'exécution est minime. Le vrai coût est encouru en créant l'exception, pas en la jetant. Selon Martin Odersky (inventeur de Scala), de nombreuses JVM peuvent en fait optimiser les instructions de lancer à sauts simples.

peut être utilisé pour simuler une coupure:

final static BREAK = new Exception();
//...
try {
  ... { throw BREAK; }
} catch (Exception ex) { /* ignored */ }
10
répondu Ralph 2010-05-24 15:01:53

Utiliser retour à continuer et tout fermeture pause .

exemple

contenu du fichier:

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

Groovy code:

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

    println line

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

sortie:

1
2
3
8
répondu Michal Z m u d a 2014-05-11 09:12:38

dans ce cas, vous devriez probablement penser à la méthode find() . Elle s'arrête après la première fois où la fermeture lui est passée.

3
répondu 0rt 2012-10-29 10:51:17

avec RX-java vous pouvez transformer un itérable en un observable.

Ensuite, vous pouvez remplacer continuer avec un filtre et pause avec takeWhile

voici un exemple:

import rx.Observable

Observable.from(1..100000000000000000)
          .filter { it % 2 != 1} 
          .takeWhile { it<10 } 
          .forEach {println it}
1
répondu frhack 2015-06-02 10:08:09