Tôi biết không có tương đương trực tiếp trong chính Java, nhưng có lẽ là một bên thứ ba?
Nó thực sự thuận tiện. Hiện tại, tôi muốn triển khai một trình lặp mang lại tất cả các nút trong một cây, có khoảng năm dòng mã có năng suất.
Tôi biết không có tương đương trực tiếp trong chính Java, nhưng có lẽ là một bên thứ ba?
Nó thực sự thuận tiện. Hiện tại, tôi muốn triển khai một trình lặp mang lại tất cả các nút trong một cây, có khoảng năm dòng mã có năng suất.
Câu trả lời:
Hai lựa chọn mà tôi biết là thư viện infomancers-collection của Aviad Ben Dov từ năm 2007 và thư viện YieldAdapter của Jim Blackler từ năm 2008 (cũng được đề cập trong câu trả lời khác).
Cả hai đều sẽ cho phép bạn viết mã với yield return
cấu trúc giống như trong Java, vì vậy cả hai đều sẽ đáp ứng yêu cầu của bạn. Sự khác biệt đáng chú ý giữa hai là:
Thư viện của Aviad đang sử dụng thao tác bytecode trong khi của Jim sử dụng đa luồng. Tùy thuộc vào nhu cầu của bạn, mỗi loại có thể có ưu và nhược điểm riêng. Có thể giải pháp của Aviad nhanh hơn, trong khi Jim's di động hơn (ví dụ: tôi không nghĩ rằng thư viện của Aviad sẽ hoạt động trên Android).
Thư viện của Aviad có giao diện gọn gàng hơn - đây là một ví dụ:
Iterable<Integer> it = new Yielder<Integer>() {
@Override protected void yieldNextCore() {
for (int i = 0; i < 10; i++) {
yieldReturn(i);
if (i == 5) yieldBreak();
}
}
};
Trong khi Jim's phức tạp hơn, đòi hỏi bạn phải có một phương pháp adept
chung chung ... ugh. Tuy nhiên, bạn có thể sử dụng một cái gì đó giống như trình bao bọc này xung quanh mã của Jim bởi Zoom Information giúp đơn giản hóa điều đó một cách đáng kể:Collector
collect(ResultHandler)
Iterable<Integer> it = new Generator<Integer>() {
@Override protected void run() {
for (int i = 0; i < 10; i++) {
yield(i);
if (i == 5) return;
}
}
};
Giải pháp của Aviad là BSD.
Giải pháp của Jim là miền công cộng và trình bao bọc của nó cũng được đề cập ở trên.
AbstractIterator
.
yield(i)
sẽ phá vỡ kể từ JDK 13, vì yield
đang được thêm vào dưới dạng một câu lệnh Java / từ khóa dành riêng mới.
Cả hai cách tiếp cận này đều có thể trở nên gọn gàng hơn một chút khi Java đã có Lambdas. Bạn có thể làm một cái gì đó như
public Yielderable<Integer> oneToFive() {
return yield -> {
for (int i = 1; i < 10; i++) {
if (i == 6) yield.breaking();
yield.returning(i);
}
};
}
Yielderable
? Nó không nên được Yieldable
? (động từ là chỉ 'năng suất', không 'yielder' hoặc 'yielderate' hoặc bất cứ điều gì)
yield -> { ... }
sẽ phá vỡ kể từ JDK 13, vì yield
đang được thêm vào như một câu lệnh Java mới / từ khóa dành riêng.
Tôi biết đó là một câu hỏi rất cũ ở đây và có hai cách được mô tả ở trên:
yield
rõ ràng có chi phí tài nguyên.Tuy nhiên, có một cách khác, thứ ba và có lẽ là cách tự nhiên nhất, để triển khai trình yield
tạo trong Java là cách triển khai gần nhất với những gì trình biên dịch C # 2.0+ làm cho yield return/break
tạo: lombok-pg . Nó hoàn toàn dựa trên một máy trạng thái và cần có sự hợp tác chặt chẽ javac
để thao tác mã nguồn AST. Thật không may, hỗ trợ lombok-pg dường như đã bị ngừng (không có hoạt động kho lưu trữ trong hơn một hoặc hai năm) và Dự án Lombok ban đầu không may thiếu yield
tính năng (mặc dù nó có IDE tốt hơn như Eclipse, hỗ trợ IntelliJ IDEA).
Stream.iterate (seed, seedOperator) .limit (n) .foreach (action) không giống như toán tử năng suất, nhưng có thể hữu ích khi viết các trình tạo của riêng bạn theo cách này:
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
}
}
Tôi cũng đề nghị nếu bạn đang sử dụng RXJava trong dự án của mình, hãy sử dụng Observable làm "yielder". Nó có thể được sử dụng theo cách tương tự nếu bạn làm cho nó có thể quan sát được.
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
}
}
Các tệp quan sát có thể được chuyển đổi thành trình vòng lặp để bạn thậm chí có thể sử dụng chúng trong các vòng lặp for truyền thống hơn. Ngoài ra RXJava cung cấp cho bạn những công cụ thực sự mạnh mẽ, nhưng nếu bạn chỉ cần một cái gì đó đơn giản thì có lẽ đây sẽ là một sự quá mức cần thiết.
Tôi vừa xuất bản một giải pháp khác (được MIT cấp phép) tại đây , này khởi chạy nhà sản xuất trong một chuỗi riêng biệt và thiết lập hàng đợi giới hạn giữa nhà sản xuất và người tiêu dùng, cho phép tạo bộ đệm, kiểm soát luồng và kết nối song song giữa nhà sản xuất và người tiêu dùng (vì vậy rằng người tiêu dùng có thể làm việc để tiêu thụ mặt hàng trước trong khi người sản xuất đang làm việc để sản xuất mặt hàng tiếp theo).
Bạn có thể sử dụng biểu mẫu lớp bên trong ẩn danh này:
Iterable<T> iterable = new Producer<T>(queueSize) {
@Override
public void producer() {
produce(someT);
}
};
ví dụ:
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);
}
Hoặc bạn có thể sử dụng ký hiệu lambda để cắt bớt trên bảng điện tử:
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);
}