Is there a Java equivalent to C#'s 'yield&

2019-01-03 23:32发布

I know there is no direct equivalent in Java itself, but perhaps a third party?

It is really convenient. Currently I'd like to implement an iterator that yields all nodes in a tree, which is about five lines of code with yield.

6条回答
forever°为你锁心
2楼-- · 2019-01-04 00:07

Stream.iterate(seed, seedOperator).limit(n).foreach(action) is not the same as yield operator, but it may be usefull to write your own generators this way:

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
    }
}
查看更多
Fickle 薄情
3楼-- · 2019-01-04 00:10

In Java 8 you could use: Stream.of

查看更多
疯言疯语
4楼-- · 2019-01-04 00:12

The two options I know of is Aviad Ben Dov's infomancers-collections library from 2007 and Jim Blackler's YieldAdapter library from 2008 (which is also mentioned in the other answer).

Both will allow you to write code with yield return-like construct in Java, so both will satisfy your request. The notable differences between the two are:

Mechanics

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).

Interface

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();
        }
    }
};

While Jim's is way more complicated, requiring you to adept a generic Collector which has a collect(ResultHandler) method... ugh. However, you could use something like this wrapper around Jim's code by Zoom Information which greatly simplifies that:

Iterable<Integer> it = new Generator<Integer>() {
    @Override protected void run() {
        for (int i = 0; i < 10; i++) {
            yield(i);
            if (i == 5) return;
        }
    }
};

License

Aviad's solution is BSD.

Jim's solution is public domain, and so is its wrapper mentioned above.

查看更多
放我归山
5楼-- · 2019-01-04 00:16

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

  • bytecode manipulation that's not that easy while porting;
  • thread-based yield that obviously has resource costs.

However, there is another, the third and probably the most natural, way of implementing the yield generator in Java that is the closest implementation to what C# 2.0+ compilers do for yield return/break generation: lombok-pg. It's fully based on a state machine, and requires tight cooperation with javac to manipulate the source code AST. Unfortunately, the lombok-pg support seems to be discontinued (no repository activity for more than a year or two), and the original Project Lombok unfortunately lacks the yield feature (it has better IDE like Eclipse, IntelliJ IDEA support, though).

查看更多
甜甜的少女心
6楼-- · 2019-01-04 00:24

Both of these approaches can be made a bit cleaner now Java has Lambdas. You can do something like

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

I explained a bit more here.

查看更多
够拽才男人
7楼-- · 2019-01-04 00:31

Here is an article on this and library from Jim Blackler that does this in Java alone.

查看更多
登录 后发表回答