闭包和java匿名内部类

时间:2012-07-20 12:19:51

标签: c# java closures

是否有人会如此善意地发布与此类(使用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#将不胜感激,但这是您的选择。 非常感谢。

3 个答案:

答案 0 :(得分:3)

Java中还没有关闭。 Lambda表达式将在Java 8中出现。但是,你试图翻译的唯一问题是它有状态,这不是lamba表达式支持的东西,我不认为。请记住,它只是一个简写,以便您可以轻松实现单个方法接口。但是你可以依旧模拟这个:

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

更简洁吧?

现在介绍lambdas:

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

看看语法有多好?你也可以链接它(我们假设有一个接口来做过滤,它返回布尔值以确定是否过滤掉一个值):

 Collection<Long> mappedAndFiltered =
    coll.map( (Foo foo) -> foo.getLong() )
        .filter( (Long val) -> val.longValue() < 1000L );

答案 1 :(得分: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
    }

}

答案 2 :(得分: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的更改不会反映在封闭范围内。这适用于此示例,因为方法中的局部变量在被闭包捕获后不会再次使用。

相反,如果您希望能够“双向”传递信息,即关闭也能够改变封闭范围内的事物,反之亦然,则需要捕获可变数据结构,像一个数组,然后更改其中的元素。这是更加丑陋的,而且很少需要这样做。