Czy istnieje Java odpowiednik słowa kluczowego C#'S 'yield'?
Wiem, że w samej Javie nie ma bezpośredniego odpowiednika, ale może jakaś trzecia strona?
To naprawdę wygodne. Obecnie chciałbym zaimplementować iterator, który daje wszystkie węzły w drzewie, czyli około pięciu linii kodu z wydajnością.
6 answers
Dwie opcje, które znam, toAviad Ben Dov 's infomancers-collections library z 2007 iJim Blackler' s yieldadapter library z 2008 (o czym również wspomniano w drugiej odpowiedzi).
Oba pozwalają na pisanie kodu z yield return
-podobnie jak construct w Javie, więc oba spełnią twoje żądanie. Różnice między nimi to:
Mechanika
Biblioteka Aviada używa manipulacji kodem bajtowym, podczas gdy Jim używa wielowątkowości. W zależności na swoje potrzeby, każdy może mieć swoje zalety i wady. Prawdopodobnie rozwiązanie Aviada jest szybsze, a Jima bardziej przenośne (na przykład nie sądzę, aby Biblioteka Aviada działała na Androidzie).
Interfejs
Biblioteka Aviada ma czystszy interfejs - oto przykład:
Iterable<Integer> it = new Yielder<Integer>() {
@Override protected void yieldNextCore() {
for (int i = 0; i < 10; i++) {
yieldReturn(i);
if (i == 5) yieldBreak();
}
}
};
Podczas gdy Jim jest o wiele bardziej skomplikowany, wymaga od ciebie adept
ogólnego Collector
, który ma metodę collect(ResultHandler)
... ugh. Możesz jednak użyć czegoś w rodzaju tego opakowania wokół Jima code by Zoom Information co znacznie upraszcza, że:
Iterable<Integer> it = new Generator<Integer>() {
@Override protected void run() {
for (int i = 0; i < 10; i++) {
yield(i);
if (i == 5) return;
}
}
};
Licencja
Rozwiązaniem Aviada jest BSD.
Rozwiązanie Jima jest domeną publiczną, podobnie jak jego opakowanie wspomniane powyżej.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-06-19 06:47:38
Oba te podejścia mogą być nieco czystsze teraz Java ma Lambda. Możesz zrobić coś takiego jak
public Yielderable<Integer> oneToFive() {
return yield -> {
for (int i = 1; i < 10; i++) {
if (i == 6) yield.breaking();
yield.returning(i);
}
};
}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-03-21 19:47:53
Wiem, że to bardzo stare pytanie i są dwa sposoby opisane powyżej:
- manipulacja kodem bajtowym, która nie jest taka łatwa podczas portowania;
- thread-based {[0] } który oczywiście ma koszty zasobów.
Istnieje jednak inny, trzeci i prawdopodobnie najbardziej naturalny sposób implementacji generatora yield
w Javie, który jest najbliższą implementacją do tego, co kompilatory C# 2.0+ robią dla generacji yield return/break
: lombok-pg . Jest w pełni oparta na stanie maszyna i wymaga ścisłej współpracy z javac
w celu manipulowania kodem źródłowym AST. Niestety, wydaje się, że wsparcie dla lombok-pg zostało przerwane (brak aktywności repozytorium przez ponad rok lub dwa), a oryginalny projekt Lombok niestety nie posiada funkcji yield
(ma jednak lepsze IDE, takie jak Eclipse, IntelliJ IDEA support).
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-03-11 08:33:04
Strumień.iterat( seed, seedOperator).limit (n).foreach (action) nie jest tym samym co operator yield, ale może być użytecznym zapisanie własnych generatorów w ten sposób:
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
}
}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-03-29 20:45:09
Sugerowałbym również, jeśli używasz już RXJava w swoim projekcie, aby użyć obserwowalnego jako "yielder". Może być stosowany w podobny sposób, jeśli stworzysz własny obserwowalny.
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
}
}
Obiekty obserwacyjne można przekształcić w Iteratory, dzięki czemu można ich używać nawet w bardziej tradycyjnych pętlach for. Również RXJava daje naprawdę potężne narzędzia, ale jeśli potrzebujesz tylko czegoś prostego, to może byłoby to przesadą.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2019-04-07 18:08:35
Właśnie opublikowałem inne (licencjonowane przez MIT) rozwiązanie tutaj , które uruchamia producenta w oddzielnym wątku i ustawia ograniczoną kolejkę między producentem a konsumentem, umożliwiając buforowanie, kontrolę przepływu i równoległe rurociągi między producentem a konsumentem (tak, że konsument może pracować nad spożywaniem poprzedniego produktu, podczas gdy producent pracuje nad produkcją następnego produktu).
Możesz użyć tej anonimowej wewnętrznej formy klasy:
Iterable<T> iterable = new Producer<T>(queueSize) {
@Override
public void producer() {
produce(someT);
}
};
Dla przykład:
for (Integer item : new Producer<Integer>(/* queueSize = */ 5) {
@Override
public void producer() {
for (int i = 0; i < 20; i++) {
System.out.println("Producing " + i);
produce(i);
}
System.out.println("Producer exiting");
}
}) {
System.out.println(" Consuming " + item);
Thread.sleep(200);
}
Lub możesz użyć notacji lambda, aby wyciąć na kotle:
for (Integer item : new Producer<Integer>(/* queueSize = */ 5, producer -> {
for (int i = 0; i < 20; i++) {
System.out.println("Producing " + i);
producer.produce(i);
}
System.out.println("Producer exiting");
})) {
System.out.println(" Consuming " + item);
Thread.sleep(200);
}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2019-12-17 00:29:21