Java'nın kendisinde doğrudan bir eşdeğeri olmadığını biliyorum, ancak belki bir üçüncü taraf?
Gerçekten uygun. Şu anda, bir ağaçtaki tüm düğümleri veren bir yineleyici uygulamak istiyorum, bu verim ile yaklaşık beş satır koddur.
Java'nın kendisinde doğrudan bir eşdeğeri olmadığını biliyorum, ancak belki bir üçüncü taraf?
Gerçekten uygun. Şu anda, bir ağaçtaki tüm düğümleri veren bir yineleyici uygulamak istiyorum, bu verim ile yaklaşık beş satır koddur.
Yanıtlar:
Bildiğim iki seçenek, Aviad Ben Dov'un 2007'deki bilgi toplama kitaplığı ve 2008'deki Jim Blackler'in YieldAdapter kitaplığıdır (diğer yanıtta da bahsedilmektedir).
Her ikisi de yield return
Java'da -like yapı ile kod yazmanıza izin verecek , böylece her ikisi de isteğinizi karşılayacaktır. İkisi arasındaki önemli farklar şunlardır:
Aviad'ın kitaplığı bayt kodu manipülasyonunu kullanırken Jim'inki çoklu okuma kullanıyor. İhtiyaçlarınıza bağlı olarak, her birinin kendi avantajları ve dezavantajları olabilir. Muhtemelen Aviad'ın çözümü daha hızlıyken Jim'inki daha taşınabilir (örneğin, Aviad'ın kütüphanesinin Android'de çalışacağını düşünmüyorum).
Aviad'ın kitaplığı daha temiz bir arayüze sahiptir - işte bir örnek:
Iterable<Integer> it = new Yielder<Integer>() {
@Override protected void yieldNextCore() {
for (int i = 0; i < 10; i++) {
yieldReturn(i);
if (i == 5) yieldBreak();
}
}
};
Jim yol daha karmaşık olsa da, sizi gerektiren adept
jenerik Collector
bir olan collect(ResultHandler)
öf ... yöntem. Bununla birlikte, Jim'in kodunun etrafında Zoom Information tarafından sağlanan bu sarmalayıcı gibi bir şey kullanabilirsiniz, bu da bunu büyük ölçüde basitleştirir:
Iterable<Integer> it = new Generator<Integer>() {
@Override protected void run() {
for (int i = 0; i < 10; i++) {
yield(i);
if (i == 5) return;
}
}
};
Aviad'ın çözümü BSD'dir.
Jim'in çözümü kamu malıdır ve yukarıda bahsedilen sarmalayıcı da öyle.
AbstractIterator
.
yield(i)
, JDK 13'ten itibaren bozulacağını unutmayın yield
.
Bu yaklaşımların her ikisi de biraz daha temiz hale getirilebilir şimdi Java'da Lambdas var. Gibi bir şey yapabilirsin
public Yielderable<Integer> oneToFive() {
return yield -> {
for (int i = 1; i < 10; i++) {
if (i == 6) yield.breaking();
yield.returning(i);
}
};
}
Yielderable
? Sadece olması gerekmiyor Yieldable
mu? (fiil sadece 'verim' olur, 'veren' veya 'verim' ya da her neyse)
yield -> { ... }
yield
Yeni bir Java ifadesi / ayrılmış anahtar kelime olarak eklendiğinden , JDK 13 itibarıyla bozulacaktır .
Bunun çok eski bir soru olduğunu biliyorum ve yukarıda açıklanan iki yol var:
yield
, açıkça kaynak maliyetleri var.Bununla birlikte, oluşturucuyu yield
Java'da uygulamanın başka, üçüncü ve muhtemelen en doğal yolu C # 2.0+ derleyicilerin yield return/break
nesil için yaptıklarına en yakın uygulama olan lombok-pg . Tamamen bir durum makinesine dayalıdır ve javac
AST kaynak kodunu işlemek için sıkı bir işbirliği gerektirir . Ne yazık ki, lombok-pg desteği kesilmiş gibi görünüyor (bir veya iki yıldan fazla bir depo aktivitesi yok) ve orijinal Project Lombok maalesef bu yield
özellikten yoksun (Eclipse, IntelliJ IDEA desteği gibi daha iyi IDE'ye sahip olsa da).
Stream.iterate (seed, seedOperator) .limit (n) .foreach (action) , verim operatörü ile aynı değildir, ancak kendi oluşturucularınızı şu şekilde yazmak yararlı olabilir:
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
}
}
Ayrıca , projenizde zaten RXJava kullanıyorsanız, bir Observable'ı "sağlayıcı" olarak kullanmak için öneriyorum . Kendi Gözlemlenebilirinizi yaparsanız benzer bir şekilde kullanılabilir.
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
}
}
Gözlenebilirler yineleyicilere dönüştürülebilir, böylece onları daha geleneksel döngülerde bile kullanabilirsiniz. Ayrıca RXJava size gerçekten güçlü araçlar sunar, ancak yalnızca basit bir şeye ihtiyacınız varsa, o zaman belki bu bir abartı olur.
Burada , üreticiyi ayrı bir iş parçacığında başlatan ve üretici ile tüketici arasında sınırlandırılmış bir kuyruk oluşturan ve üretici ile tüketici arasında arabelleğe alma, akış kontrolü ve paralel boru hattına izin veren başka bir (MIT lisanslı) çözüm yayınladım (yani Üretici bir sonraki ürünü üretmeye çalışırken tüketici önceki ürünü tüketmeye çalışıyor olabilir).
Bu anonim iç sınıf formunu kullanabilirsiniz:
Iterable<T> iterable = new Producer<T>(queueSize) {
@Override
public void producer() {
produce(someT);
}
};
Örneğin:
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);
}
Veya standart metinde kısmak için lambda gösterimini kullanabilirsiniz:
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);
}