web-dev-qa-db-fra.com

Existe-t-il un Java équivalent au mot-clé 'yield' de C #?

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.

103
ripper234

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:

Mécanique

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).

Interface

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

Licence

La solution d'Aviad est BSD.

La solution de Jim est du domaine public, tout comme son enveloppe mentionnée ci-dessus.

88
Oak

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

J'ai expliqué un peu plus ici.

12
benjiweber

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
    }
}
1
Andrey Lavrukhin

Je sais que c'est une très vieille question ici, et il y a deux façons décrites ci-dessus:

  • manipulation de bytecode qui n'est pas si simple lors du portage;
  • basé sur les threads 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).

1
Lyubomyr Shaydariv

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é.

0
Győri Sándor