有没有Java相当于C#的'yield'关键字?
我知道Java本身没有直接的等价物,但也许是第三方?
这真的很方便。 目前我想实现一个迭代器,它产生一个树中的所有节点,大约有五行代码和yield。
我所知道的两个选项是2007年的Aviad Ben Dov的infomancers-collections图书馆和2008年的Jim Blackler的YieldAdapter图书馆 (在另一个答案中也提到过)。
两者都将允许您使用Java中的yield return
类构造编写代码,因此两者都将满足您的请求。 两者之间的显着差异是:
机械学
Aviad的库使用字节码操作,而Jim的使用multithreading。 根据你的需求,每个人都有自己的优点和缺点。 Aviad的解决scheme很可能会更快,而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(); } } };
而吉姆的方式更复杂,要求你adept
使用一个collect(ResultHandler)
方法的通用Collector
…呃。 但是,您可以使用缩放信息在Jim的代码中使用类似这种包装的东西,这大大简化了:
Iterable<Integer> it = new Generator<Integer>() { @Override protected void run() { for (int i = 0; i < 10; i++) { yield(i); if (i == 5) return; } } };
执照
Aviad的解决scheme是BSD。
Jim的解决scheme是公有领域,上面提到的包装也是如此。
这里是关于这个和Jim Blackler的图书馆的文章,只在Java中做这个。
现在Java有Lambdas,这两种方法都可以做得更清洁一些。 你可以做类似的事情
public Yielderable<Integer> oneToFive() { return yield -> { for (int i = 1; i < 10; i++) { if (i == 6) yield.breaking(); yield.returning(i); } }; }
我在这里解释了一下。
我知道这是一个非常古老的问题,上面介绍了两种方法:
- 字节码操作在移植时并不那么容易;
- 基于线程的
yield
显然有资源成本。
然而,在Java中实现yield
产生器的另外一种,也许是最自然的方式是与C#2.0+编译器为yield return/break
产生做的最接近的实现: lombok-pg 。 它完全基于一个状态机,并且需要与javac
紧密合作才能操纵源代码AST。 不幸的是,lombok-pg的支持似乎已经停止(没有一两年的存储库活动),原始的Project Lombok不幸缺lessyield
特性(尽pipeEclipse有更好的IDE,但支持IntelliJ IDEA)。
Stream.iterate(seed,seedOperator).limit(n).foreach(action)与yield运算符不一样,但用这种方法编写自己的生成器可能是有用的:
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 } }
在Java 8中,您可以使用: Stream.of