1

匿名の内部クラスを使用して、このようなクロージャ(C#を使用して取得)の同等のJavaコードを投稿してくれる人はいますか?

    public static Func<int, int> IncrementByN()
    {
        int n = 0; // n is local to the method

        Func<int, int> increment = delegate(int x)
        {
            n++;
            return x + n;
        };

        return increment;
    }
static void Main(string[] args)
   {

        var v = IncrementByN();
        Console.WriteLine(v(5)); // output 6
        Console.WriteLine(v(6)); // output 8
    }

さらに、字句クロージャが利用可能であり、その逆の場合に部分適用を取得する方法を誰かが説明できますか?この2番目の質問については、C#をいただければ幸いですが、それはあなたの選択です。本当にありがとう。

4

3 に答える 3

3

Javaにはまだクロージャはありません。ラムダ式はJava8で提供されます。ただし、翻訳しようとしているものの唯一の問題は、状態があることです。これは、ランバ式がサポートするものではないと思います。単一のメソッドインターフェイスを簡単に実装できるように、これは実際には単なる省略形であることに注意してください。ただし、これをシミュレートすることはできます。

final AtomicInteger n = new AtomicInteger(0);
IncrementByN v = (int x) -> x + n.incrementAndGet();
System.out.println(v.increment(5));
System.out.println(v.increment(6));

ただし、このコードはテストしていません。これは、Java8で機能する可能性のあるものの例としてのみ使用されています。

コレクションAPIについて考えてみてください。彼らがこのインターフェースを持っているとしましょう:

public interface CollectionMapper<S,T> {
    public T map(S source);
}

そして、java.util.Collectionのメソッド:

public interface Collection<K> {
  public <T> Collection<T> map(CollectionMapper<K,T> mapper);
}

さて、クロージャなしでそれを見てみましょう:

Collection<Long> mapped = coll.map(new CollectionMapper<Foo,Long>() {
    public Long map(Foo foo) {
       return foo.getLong();
    }
}

なぜこれを書いてみませんか:

Collection<Long> mapped = ...;
for (Foo foo : coll) {
    mapped.add(foo.getLong());
}

もっと簡潔でしょ?

次にラムダを導入します。

Collection<Long> mapped = coll.map( (Foo foo) -> foo.getLong() );

構文がどれほど優れているか見てみましょう。また、チェーン化することもできます(値をフィルターで除外するかどうかを決定するためにブール値を返す、フィルタリングを実行するためのインターフェイスがあると想定します)。

 Collection<Long> mappedAndFiltered =
    coll.map( (Foo foo) -> foo.getLong() )
        .filter( (Long val) -> val.longValue() < 1000L );
于 2012-07-20T12:50:41.000 に答える
0

このコードは私が信じているのと同等です(少なくともそれは望ましい出力を生成します):

public class Test {

    static interface IncrementByN {
        int increment(int x);
    }

    public static void main(String[] args) throws InterruptedException {
        IncrementByN v = new IncrementByN() { //anonymous class
            int n = 0;

            @Override
            public int increment(int x) {
                n++;
                return x + n;
            }
        };
        System.out.println(v.increment(5)); // output 6
        System.out.println(v.increment(6)); // output 8
    }

}
于 2012-07-20T12:28:39.133 に答える
0

ジェネリック関数インターフェースがあると仮定します。

public interface Func<A, B> {
    B call A();
}

次に、次のように記述できます。

public class IncrementByN {

    public static Func<Integer, Integer> IncrementByN()
    {
        final int n_outer = 0; // n is local to the method

        Func<Integer, Integer> increment = new Func<Integer, Integer>() {
            int n = n_outer; // capture it into a non-final instance variable
                             // we can really just write int n = 0; here
            public Integer call(Integer x) {
                n++;
                return x + n;
            }
        };

        return increment;
    }
    public static void main(String[] args) {
        Func<Integer, Integer> v = IncrementByN();
        System.out.println(v.call(5)); // output 6
        System.out.println(v.call(6)); // output 8
    }
}

いくつかのメモ:

プログラムでは、囲んでいるスコープから参照によって変数をキャプチャnし、クロージャからその変数を変更できます。Javaでは、final変数のみをキャプチャできます(したがって、キャプチャは値によってのみ行われます)。

ここで行ったことはfinal、外部から変数をキャプチャし、それをfinal匿名クラス内の非インスタンス変数に割り当てることです。これにより、クロージャーに「情報を渡す」と同時に、クロージャー内で情報を割り当てることができます。ただし、この情報フローは「一方向」でのみ機能しnます。クロージャ内への変更は、囲んでいるスコープには反映されません。メソッド内のローカル変数は、クロージャーによってキャプチャされた後は再び使用されないため、これはこの例に適しています。

代わりに、情報を「双方向」に渡すことができるようにしたい場合、つまり、クロージャーが囲んでいるスコープ内のものを変更できるようにしたい場合、またはその逆の場合は、代わりに配列などの可変データ構造をキャプチャする必要があります、次にその中の要素に変更を加えます。それは醜く、必要になることはめったにありません。

于 2012-07-20T18:03:36.997 に答える