Esiste un equivalente Java alla parola chiave ‘yield’ di C #?

So che non esiste un equivalente diretto in Java, ma forse una terza parte?

È davvero conveniente Attualmente mi piacerebbe implementare un iteratore che produce tutti i nodes in un albero, che è di circa cinque righe di codice con rendimento.

Le due opzioni che conosco sono la biblioteca di Avom Ben-Ben – raccolte di collezioni – del 2007 e la biblioteca YieldAdapter di Jim Blackler del 2008 (che è menzionata anche nell’altra risposta).

Entrambi ti permetteranno di scrivere codice con costrutto -come yield return in Java, quindi entrambi soddisferanno la tua richiesta. Le notevoli differenze tra i due sono:

Meccanica

La libreria di Aviad utilizza la manipolazione bytecode mentre Jim usa il multithreading. A seconda delle esigenze, ognuno può avere i suoi vantaggi e svantaggi. È probabile che la soluzione di Aviad sia più veloce, mentre quella di Jim è più portabile (ad esempio, non credo che la libreria di Aviad funzioni su Android).

Interfaccia

La libreria di Aviad ha un’interfaccia più pulita – ecco un esempio:

 Iterable it = new Yielder() { @Override protected void yieldNextCore() { for (int i = 0; i < 10; i++) { yieldReturn(i); if (i == 5) yieldBreak(); } } }; 

Mentre Jim è molto più complicato, richiedendoti di adept un Collector generico che ha un metodo collect(ResultHandler) ... ugh. Tuttavia, è ansible utilizzare qualcosa come questo involucro attorno al codice di Jim da Zoom Information che semplifica enormemente questo:

 Iterable it = new Generator() { @Override protected void run() { for (int i = 0; i < 10; i++) { yield(i); if (i == 5) return; } } }; 

Licenza

La soluzione di Aviad è BSD.

La soluzione di Jim è di dominio pubblico, così come il suo wrapper menzionato sopra.

Ecco un articolo su questo e una libreria di Jim Blackler che fa questo solo in Java.

Entrambi questi approcci possono essere resi un po ‘più puliti ora Java ha Lambdas. Puoi fare qualcosa del genere

 public Yielderable oneToFive() { return yield -> { for (int i = 1; i < 10; i++) { if (i == 6) yield.breaking(); yield.returning(i); } }; } 

Ho spiegato un po 'di più qui.

So che è una domanda molto vecchia qui, e ci sono due modi descritti sopra:

  • manipolazione bytecode che non è così semplice durante il porting;
  • yield basato su thread che ovviamente ha costi di risorse.

Tuttavia, c’è un altro, il terzo e probabilmente il modo più naturale di implementare il generatore di yield in Java che è l’implementazione più vicina a ciò che fanno i compilatori C # 2.0+ per la generazione di yield return/break : lombok-pg . È completamente basato su una macchina a stati e richiede una stretta collaborazione con javac per manipolare il codice sorgente AST. Sfortunatamente, il supporto lombok-pg sembra essere sospeso (nessuna attività di repository per più di un anno o due), e il Project Lombok originale sfortunatamente manca della feature yield (ha IDE migliore come Eclipse, IntelliJ IDEA support, sebbene).

Stream.iterate (seed, seedOperator) .limit (n) .foreach (action) non è lo stesso operatore di yield, ma può essere utile scrivere i tuoi generatori in questo modo:

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

In Java 8 è ansible utilizzare: Stream.of