Je sais qu'il n'y a pas d'équivalent direct dans Java lui-même, mais peut-être un tiers?
C'est vraiment pratique. Actuellement, j'aimerais implémenter un itérateur qui produit tous les nœuds dans une arborescence, soit environ cinq lignes de code avec yield.
Les deux options que je connais sont bibliothèque des collections d'infomancers d'Aviad Ben Dov de 2007 et bibliothèque YieldAdapter de Jim Blackler de 2008 (qui est également mentionnée dans l'autre réponse).
Les deux vous permettront d'écrire du code avec une construction similaire à yield return
En Java, donc les deux satisferont votre demande. Les différences notables entre les deux sont:
La bibliothèque d'Aviad utilise la manipulation de bytecode tandis que celle de Jim utilise le multithreading. Selon vos besoins, chacun peut avoir ses propres avantages et inconvénients. Il est probable que la solution d'Aviad soit plus rapide, tandis que celle de Jim est plus portable (par exemple, je ne pense pas que la bibliothèque d'Aviad fonctionnera sur Android).
La bibliothèque d'Aviad a une interface plus propre - voici un exemple:
Iterable<Integer> it = new Yielder<Integer>() {
@Override protected void yieldNextCore() {
for (int i = 0; i < 10; i++) {
yieldReturn(i);
if (i == 5) yieldBreak();
}
}
};
Alors que Jim est beaucoup plus compliqué, vous obligeant à adept
un générique Collector
qui a une méthode collect(ResultHandler)
... ugh. Cependant, vous pouvez utiliser quelque chose comme ce wrapper autour du code de Jim par Zoom Information ce qui simplifie grandement cela:
Iterable<Integer> it = new Generator<Integer>() {
@Override protected void run() {
for (int i = 0; i < 10; i++) {
yield(i);
if (i == 5) return;
}
}
};
La solution d'Aviad est BSD.
La solution de Jim est du domaine public, tout comme son enveloppe mentionnée ci-dessus.
Ces deux approches peuvent être rendues un peu plus propres maintenant Java a Lambdas. Vous pouvez faire quelque chose comme
public Yielderable<Integer> oneToFive() {
return yield -> {
for (int i = 1; i < 10; i++) {
if (i == 6) yield.breaking();
yield.returning(i);
}
};
}
Stream.iterate (seed, seedOperator) .limit (n) .foreach (action) n'est pas le même que l'opérateur yield, mais il peut être utile d'écrire vos propres générateurs de cette façon:
import Java.util.stream.Stream;
public class Test01 {
private static void myFoo(int someVar){
//do some work
System.out.println(someVar);
}
private static void myFoo2(){
//do some work
System.out.println("some work");
}
public static void main(String[] args) {
Stream.iterate(1, x -> x + 1).limit(15).forEach(Test01::myFoo); //var1
Stream.iterate(1, x -> x + 1).limit(10).forEach(item -> myFoo2()); //var2
}
}
Je sais que c'est une très vieille question ici, et il y a deux façons décrites ci-dessus:
yield
qui a évidemment des coûts de ressources.Cependant, il existe une autre façon, la troisième et probablement la plus naturelle, d'implémenter le générateur yield
dans Java qui est l'implémentation la plus proche de ce que les compilateurs C # 2.0+ font pour yield return/break
génération: lombok-pg . Il est entièrement basé sur une machine à états et nécessite une coopération étroite avec javac
pour manipuler le code source AST. Malheureusement, le support de lombok-pg semble être interrompu (pas d'activité de référentiel pendant plus d'un an ou deux), et l'original Project Lombok n'a malheureusement pas la fonction yield
(il a mieux IDE comme Eclipse, IntelliJ IDEA, cependant).
Je suggérerais également si vous utilisez déjà RXJava dans votre projet d'utiliser un observable comme "yielder". Il peut être utilisé de manière similaire si vous créez votre propre Observable.
public class Example extends Observable<String> {
public static void main(String[] args) {
new Example().blockingSubscribe(System.out::println); // "a", "b", "c", "d"
}
@Override
protected void subscribeActual(Observer<? super String> observer) {
observer.onNext("a"); // yield
observer.onNext("b"); // yield
observer.onNext("c"); // yield
observer.onNext("d"); // yield
observer.onComplete(); // finish
}
}
Les observables peuvent être transformés en itérateurs afin que vous puissiez même les utiliser dans des boucles plus traditionnelles. De plus, RXJava vous donne des outils vraiment puissants, mais si vous n'avez besoin que de quelque chose de simple, alors ce serait peut-être exagéré.