是否有一个 Java 等价于 C # 的“屈服”关键字?

我知道 Java 本身没有直接的等价物,但是可能有第三方?

真的很方便。目前,我想实现一个迭代器,它产生一个树中的所有节点,这是大约5行代码的产出。

38575 次浏览

我所知道的两个选项是 Aviad Ben Dov's infomancers-collections library from 2007Jim Blackler 2008年的 YieldAdapter 库(另一个答案中也提到了这两个选项)。

它们都允许您用 Java 编写具有类似 yield return结构的代码,因此都将满足您的请求。两者之间的显著区别是:

机械师

Aviad's library is using bytecode manipulation while Jim's uses multithreading. Depending on your needs, each may have its own advantages and disadvantages. It's likely Aviad's solution is faster, while Jim's is more portable (for example, I don't think Aviad's library will work on Android).

接口

Aviad's library has a cleaner interface - here's an example:

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)方法... 呃。然而,你可以使用像 这个包装吉姆代码的包装纸是极速信息公司提供的这样的东西,它大大简化了:

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。

Jim 的解决方案是公共领域,上面提到的包装器也是如此。

I know it's a very old question here, and there are two ways described above:

  • 字节码操作,移植时不那么容易;
  • 显然具有资源成本的基于线程的 yield

然而,还有另一种,也许是最自然的,在 Java 中实现 yield生成器的方法,它是最接近 C # 2.0 + 编译器为 yield return/break生成所做的实现: Lombok-pg。它完全基于状态机,需要与 javac紧密合作来操作源代码 AST。不幸的是,Lombok-pg 支持似乎已经停止了(一两年内没有存储库活动) ,原来的 Project Lombok不幸缺少 yield特性(不过它有更好的 IDE,比如 Eclipse、 IntelliJ IDEA 支持)。

现在 Java 已经有了 Lambdas,这两种方法都可以变得更简洁一些

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

我在这里多解释了一点。

Iterate (种子,籽操作符)。限额(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,那么可以使用 Observer 作为“屈服者”。如果你自己做一个可观察的,它也可以以类似的方式使用。

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

可观察对象可以转换为迭代器,因此您甚至可以在更传统的 for 循环中使用它们。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);
}

Or you can use lambda notation to cut down on boilerplate:

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);
}
// Java code for Stream.generate()
// to generate an infinite sequential
// unordered stream
import java.util.*;
import java.util.stream.Stream;
  

class GFG {
      

// Driver code
public static void main(String[] args) {
      

// using Stream.generate() method
// to generate 5 random Integer values
Stream.generate(new Random()::nextInt)
.limit(5).forEach(System.out::println);
}
}

从这里。