是否有一个Java等价于C#&x27;s';收益率';关键词?

是否有一个Java等价于C#&x27;s';收益率';关键词?,java,yield,yield-return,Java,Yield,Yield Return,我知道Java本身没有直接的等价物,但也许是第三方 真的很方便。目前,我想实现一个迭代器,它可以生成树中的所有节点,这大约是五行代码,并且有收益。我知道的两个选项是and(另一个答案中也提到了这一点) 两者都允许您使用Java中的yield return类构造编写代码,因此两者都可以满足您的请求。两者之间的显著区别是: 机械 Aviad的库使用字节码操作,而Jim的库使用多线程。根据您的需要,每种方法都有各自的优缺点。很可能Aviad的解决方案速度更快,而Jim的则更具可移植性(例如,我认为Av

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


真的很方便。目前,我想实现一个迭代器,它可以生成树中的所有节点,这大约是五行代码,并且有收益。

我知道的两个选项是and(另一个答案中也提到了这一点)

两者都允许您使用Java中的
yield return
类构造编写代码,因此两者都可以满足您的请求。两者之间的显著区别是:

机械 Aviad的库使用字节码操作,而Jim的库使用多线程。根据您的需要,每种方法都有各自的优缺点。很可能Aviad的解决方案速度更快,而Jim的则更具可移植性(例如,我认为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();
        }
    }
};
许可证 Aviad的解决方案是BSD


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

我知道这是一个非常古老的问题,上面介绍了两种方法:

  • 字节码操作在移植时不是那么容易
  • 基于线程的
    产量
    ,显然有资源成本

然而,在Java中实现
yield
生成器还有另一种方法,也是第三种,可能也是最自然的方法,它与C#2.0+编译器在
yield return/break
生成中所做的最接近。它完全基于状态机,需要与
javac
紧密合作来操作源代码。不幸的是,lombok pg支持似乎已经停止了(一两年内没有任何存储库活动),而且很不幸,最初的版本缺少
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);
        }
    };
}
public Yielderable oneToFive(){
收益率->{
对于(int i=1;i<10;i++){
如果(i==6)屈服.断裂();
收益率。收益率(i);
}
};
}
Stream.iterate(seed,seedOperator).limit(n).foreach(action)与yield operator不同,但可以这样编写自己的生成器:

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

我还建议,如果你已经在你的项目中使用了一个可观察对象作为“yielder”。如果你让你自己的观察到的话,它也可以以类似的方式使用

公共类示例扩展了可观察的{
公共静态void main(字符串[]args){
新示例().blockingSubscribe(System.out::println);/“a”、“b”、“c”、“d”
}
@凌驾
protectedvoid subscribeActual(Observer我刚刚发布了另一个(MIT许可的)解决方案,它在一个单独的线程中启动生产者,并在生产者和消费者之间建立一个有界队列,允许生产者和消费者之间进行缓冲、流控制和并行管道(这样消费者就可以在生产商生产下一个产品的同时消费上一个产品)

您可以使用此匿名内部类表单:

Iterable<T> iterable = new Producer<T>(queueSize) {
    @Override
    public void producer() {
        produce(someT);
    }
};
Iterable Iterable=新生产者(队列大小){
@凌驾
公共空间生产者(){
生产(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(整数项:新生产者(/*queueSize=*/5){
@凌驾
公共空间生产者(){
对于(int i=0;i<20;i++){
系统输出打印项次(“生成”+i);
生产(一);
}
System.out.println(“生产商退出”);
}
}) {
系统输出打印项次(“消费”+项目);
睡眠(200);
}
或者,您可以使用lambda表示法来减少样板文件:

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);
}
for(整数项:新生产者(/*queueSize=*/5,生产者->{
对于(int i=0;i<20;i++){
系统输出打印项次(“生成”+i);
生产者.产品(i);
}
System.out.println(“生产商退出”);
})) {
系统输出打印项次(“消费”+项目);
睡眠(200);
}

我知道,我知道。但我认为了解更多的语言会更有力量。此外,我现在工作的公司的后端开发(我正在做)是用Java完成的,所以我不能真正选择语言:(精彩的回答。你不仅完整地回答了这个问题,而且回答得非常清楚。而且,我喜欢你的回答格式以及你如何包含许可证信息。继续回答这个问题吧!:)别忘了番石榴。我刚刚发布了另一个(麻省理工学院许可)这里的解决方案为生产者启动一个单独的线程,并在生产者和消费者之间建立一个有界队列:github.com/lukehutch/producer
Yieldable
?它不应该是
Yieldable
?(动词只是'yield',而不是'yielder'或'yieldarate'或其他任何东西)
Yieldable->{…}
将从JDK 13起中断,因为
yield
将作为新的Java语句/保留关键字添加。@LukeHutchison不,不会。仅调用名为“
yield
的方法要求限定表达式或类型与
yield
语句区分开来。命名变量
yield
并使用它不需要任何更改。
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);
}