web-dev-qa-db-ja.com

Java C#の 'yield'キーワードに相当するものはありますか?

Java自体に直接相当するものはありませんが、おそらくサードパーティですか?

本当に便利です。現在、ツリー内のすべてのノードを生成するイテレーターを実装したいと思います。これは、生成されたコードの約5行です。

103
ripper234

私が知っている2つのオプションは、 2007年のAviad Ben Dovのinfomancers-collectionsライブラリ2008年のJim BlacklerのYieldAdapterライブラリ です(他の回答でも言及されています)。

どちらも、Javaで_yield return_- like構造を使用してコードを記述できるため、両方とも要求を満たすことができます。 2つの違いは次のとおりです。

力学

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

Jimはもっと複雑ですが、adeptcollect(ResultHandler)メソッドを持つ汎用Collectorを要求します...うーん。ただし、 Zoom Informationによる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のソリューションはBSDです。

Jimのソリューションはパブリックドメインであり、前述のラッパーも同様です。

88
Oak

これらのアプローチは両方とも今より少しきれいにすることができますJavaにはラムダがあります。

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

ここでもう少し説明しました

12
benjiweber

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

ここでは非常に古い質問であり、上記の2つの方法があります。

  • 移植中はそれほど簡単ではないバイトコード操作。
  • スレッドベースのyieldには明らかにリソースコストがあります。

ただし、yieldジェネレータをJavaに実装する別の、3番目の、おそらく最も自然な方法があります。これは、C#2.0+コンパイラがyield return/breakに対して行う最も近い実装です。 generation: lombok-pg 。ステートマシンに完全に基づいており、ソースコードASTを操作するにはjavacとの緊密な協力が必要です。残念ながら、lombok-pgのサポートは中止されたようです。 (1〜2年以上リポジトリ活動がありません)、元の Project Lombok は残念ながらyield機能を欠いています(IDE Eclipse、IntelliJ IDEAサポート、ただし)。

1

また、プロジェクトで RXJava を使用してObservableを "yielder"として使用している場合もお勧めします。独自のObservableを作成する場合、同様の方法で使用できます。

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

Observableはイテレータに変換できるため、従来のforループでも使用できます。また、RXJavaは非常に強力なツールを提供しますが、シンプルなものだけが必要な場合、これはやり過ぎかもしれません。

0
Győri Sándor