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
    }

此外,如果词法闭包可用,任何人都可以解释如何获得部分应用程序,反之亦然?对于第二个问题,C# 将不胜感激,但这是您的选择。非常感谢。

4

3 回答 3

3

Java 中还没有闭包。Lambda 表达式将出现在 java 8 中。但是,您尝试翻译的唯一问题是它具有状态,我认为这不是 lambda 表达式将支持的。请记住,它实际上只是一个简写,以便您可以轻松实现单一方法接口。但是,您仍然可以模拟这一点,我相信:

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

虽然我没有测试过这段代码,它只是作为一个例子来说明可能在 java 8 中工作的内容。

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

更简洁对吧?

现在介绍 lambda:

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 回答