ฉันรู้ว่าไม่มีการเทียบเท่าโดยตรงใน Java แต่อาจเป็นของบุคคลที่สาม?
มันสะดวกมาก ตอนนี้ฉันต้องการใช้ตัววนซ้ำที่ให้โหนดทั้งหมดในทรีซึ่งเป็นโค้ดประมาณห้าบรรทัดพร้อมผลตอบแทน
ฉันรู้ว่าไม่มีการเทียบเท่าโดยตรงใน Java แต่อาจเป็นของบุคคลที่สาม?
มันสะดวกมาก ตอนนี้ฉันต้องการใช้ตัววนซ้ำที่ให้โหนดทั้งหมดในทรีซึ่งเป็นโค้ดประมาณห้าบรรทัดพร้อมผลตอบแทน
คำตอบ:
สองตัวเลือกที่ฉันรู้จักคือไลบรารีคอลเลกชัน infomancers ของ Aviad Ben Dov จากปี 2550และห้องสมุด YieldAdapter ของ Jim Blackler จากปี 2008 (ซึ่งกล่าวถึงในคำตอบอื่น ๆ ด้วย)
ทั้งสองจะช่วยให้คุณสามารถเขียนโค้ดด้วยyield return
โครงสร้าง -like ใน Java ดังนั้นทั้งสองจะตอบสนองคำขอของคุณ ความแตกต่างที่โดดเด่นระหว่างทั้งสองคือ:
ไลบรารีของ Aviad ใช้การจัดการ bytecode ในขณะที่ Jim's ใช้มัลติเธรด ขึ้นอยู่กับความต้องการของคุณแต่ละคนอาจมีข้อดีและข้อเสียของตัวเอง เป็นไปได้ว่าโซลูชันของ Aviad จะเร็วกว่าในขณะที่ Jim's พกพาสะดวกกว่า (เช่นฉันไม่คิดว่าไลบรารีของ Aviad จะทำงานบน Android)
ไลบรารีของ Aviad มีอินเทอร์เฟซที่สะอาดกว่า - นี่คือตัวอย่าง:
Iterable<Integer> it = new Yielder<Integer>() {
@Override protected void yieldNextCore() {
for (int i = 0; i < 10; i++) {
yieldReturn(i);
if (i == 5) yieldBreak();
}
}
};
ในขณะที่จิมมีความซับซ้อนกว่า แต่ต้องการให้คุณadept
ใช้ยาสามัญCollector
ซึ่งมีcollect(ResultHandler)
วิธีการ ... ฮึ อย่างไรก็ตามคุณสามารถใช้กระดาษห่อหุ้มรอบรหัสของ Jim ได้โดย Zoom Informationซึ่งช่วยให้ง่ายขึ้นมาก:
Iterable<Integer> it = new Generator<Integer>() {
@Override protected void run() {
for (int i = 0; i < 10; i++) {
yield(i);
if (i == 5) return;
}
}
};
โซลูชันของ Aviad คือ BSD
โซลูชันของจิมเป็นสาธารณสมบัติดังนั้นกระดาษห่อหุ้มที่กล่าวถึงข้างต้น
AbstractIterator
อย่าลืมของฝรั่ง
yield(i)
จะแตกเป็น JDK 13 เนื่องจากyield
จะถูกเพิ่มเป็นคำสั่ง Java ใหม่ / คีย์เวิร์ดที่สงวนไว้
ทั้งสองวิธีนี้สามารถทำความสะอาดได้เล็กน้อยตอนนี้ Java มี Lambdas แล้ว คุณสามารถทำสิ่งที่ชอบ
public Yielderable<Integer> oneToFive() {
return yield -> {
for (int i = 1; i < 10; i++) {
if (i == 6) yield.breaking();
yield.returning(i);
}
};
}
Yielderable
เหรอ? มันควรจะไม่ใช่Yieldable
เหรอ? (คำกริยาที่เป็นเพียง 'ให้ผล' ไม่ใช่ 'yielder' หรือ 'ยอมแพ้' หรืออะไรก็ตาม)
yield -> { ... }
จะหยุดทำงานเมื่อ JDK 13 เนื่องจากyield
จะถูกเพิ่มเป็นคำสั่ง Java ใหม่ / คีย์เวิร์ดที่สงวนไว้
ฉันรู้ว่ามันเป็นคำถามเก่ามากที่นี่และมีสองวิธีที่อธิบายไว้ข้างต้น:
yield
ที่เห็นได้ชัดว่ามีต้นทุนทรัพยากรอย่างไรก็ตามมีอีกครั้งที่สามและอาจจะเป็นธรรมชาติมากที่สุดวิธีการของการใช้yield
เครื่องกำเนิดไฟฟ้าใน Java ที่เป็นการดำเนินงานใกล้เคียงกับสิ่ง C # 2.0 + คอมไพเลอร์ทำเพื่อyield return/break
รุ่น: ลอมบอก-PG มันขึ้นอยู่กับเครื่องของรัฐอย่างสมบูรณ์และต้องการความร่วมมืออย่างแน่นหนาjavac
เพื่อจัดการกับซอร์สโค้ด AST น่าเสียดายที่ดูเหมือนว่าการสนับสนุน lombok-pg จะหยุดให้บริการ (ไม่มีกิจกรรมพื้นที่เก็บข้อมูลนานกว่าหนึ่งปีหรือสองปี) และProject Lombokดั้งเดิมขาดyield
คุณสมบัตินี้ไปอย่างน่าเสียดาย(มี IDE ที่ดีกว่าเช่น Eclipse, IntelliJ IDEA)
Stream.iterate (seed, seedOperator) .limit (n) .foreach (action)ไม่เหมือนกับตัวดำเนินการให้ผลผลิต แต่อาจเป็นประโยชน์ในการเขียนเครื่องกำเนิดไฟฟ้าของคุณเองด้วยวิธีนี้:
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
}
}
ฉันขอแนะนำด้วยว่าคุณใช้RXJavaในโปรเจ็กต์ของคุณอยู่แล้วหรือไม่เพื่อใช้ Observable เป็น "yielder" สามารถใช้ในลักษณะคล้ายกันได้หากคุณสร้าง 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
}
}
Observables สามารถเปลี่ยนเป็นตัววนซ้ำเพื่อให้คุณสามารถใช้มันในแบบดั้งเดิมสำหรับลูปได้มากขึ้น นอกจากนี้ RXJava ยังให้เครื่องมือที่ทรงพลังแก่คุณ แต่ถ้าคุณต้องการเพียงแค่บางสิ่งที่เรียบง่ายนั่นอาจจะเป็นการใช้งานมากเกินไป
ฉันเพิ่งเผยแพร่โซลูชันอื่น (ที่ได้รับอนุญาตจาก MIT) ที่นี่ซึ่งเปิดตัวผู้ผลิตในเธรดแยกต่างหากและตั้งค่าคิวที่มีขอบเขตระหว่างผู้ผลิตและผู้บริโภคทำให้สามารถบัฟเฟอร์การควบคุมการไหลและการวางท่อคู่ขนานระหว่างผู้ผลิตและผู้บริโภค (ดังนั้น ผู้บริโภคสามารถดำเนินการเพื่อบริโภครายการก่อนหน้าในขณะที่ผู้ผลิตกำลังดำเนินการผลิตรายการถัดไป)
คุณสามารถใช้แบบฟอร์มคลาสภายในที่ไม่ระบุชื่อนี้:
Iterable<T> iterable = new Producer<T>(queueSize) {
@Override
public void producer() {
produce(someT);
}
};
ตัวอย่างเช่น:
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);
}
หรือคุณสามารถใช้สัญกรณ์แลมบ์ดาเพื่อตัดลงบนแผ่นสำเร็จรูป:
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);
}