首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >蓄电池发生器测试- Java 8

蓄电池发生器测试- Java 8
EN

Stack Overflow用户
提问于 2014-06-06 13:23:14
回答 1查看 1.8K关注 0票数 7

保罗·格雷厄姆( Paul )在他的伟大文章“书呆子的复仇”(书呆子的复仇)中声称,语言在权力上各不相同。他提到了一个很好的练习--写了一个累加器生成器:

我们想要写一个函数来生成累加器--一个函数,它接受一个数字n,并返回一个函数,这个函数接受另一个数字i,并返回n个递增的i。

Java的解决方案是

代码语言:javascript
复制
public class Accumulator {

    public interface Inttoint {
        public int call(int i);
    }

    public static Inttoint foo(final int n) {
        return new Inttoint() {
            int s = n;
            public int call(int i) {
                s = s + i;
                return s;
            }};
    }

    public static void main(String... args) {
        Inttoint accumulator = foo(1);

        System.out.println(accumulator.call(2) == 3);
        System.out.println(accumulator.call(3) == 6);
    }

}

我很好奇,在Java 8 (感谢lambda)中,是否已经有了一些优雅的方法来将其编写成类似于,请参见下面的内容。我试过Function<Integer, Integer>

但我坚持这个编译器错误。

从lambda表达式引用的局部变量必须是最终变量或有效的最终变量。

那么,您有一些Java 8解决方案吗?

将旧Java解决方案与Groovy解决方案进行比较

代码语言:javascript
复制
def foo(n) {
    return {n += it}
}

def accumulator = foo(1)
assert accumulator(2) == 3
assert accumulator(3) == 6
EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2014-06-06 13:35:42

首先,您仍然可以使用匿名类语法而不是lambda语法使用所有新的Java 8接口。例如:

代码语言:javascript
复制
import java.util.function.IntUnaryOperator;

public class Accumulator {
    public static IntUnaryOperator foo(int n) {
        return new IntUnaryOperator() {
            private int value = n;
            @Override
            public int applyAsInt(int i) {
                return value += i;
            }
        };
    }

    public static void main(String... args) {
        IntUnaryOperator accumulator = foo(1);
        System.out.println(accumulator.applyAsInt(2)); // output: 3
        System.out.println(accumulator.applyAsInt(3)); // output: 6
    }
}

(我在这里使用的不是Function,而是IntUnaryOperator,因为它允许使用原始ints而不是装箱的Integers。如果这是合法的话,这在逻辑上相当于Function<int,int>。)

现在,我们如何用lambda语法来缩短这个庞大的东西呢?传递给lambda的局部变量必须是(有效的) final。这个限制意味着您不能轻松地编写一个变量,其值在调用之间累积。以下内容不起作用:

代码语言:javascript
复制
public static IntUnaryOperator foo(int n) {
    return i -> n += i; // nope, sorry!
}

我们可以通过使用某个可变对象作为当前累加器值的持卡器来解决这个限制。为此可以使用一个单元素数组。数组变量没有变化,只有它指向的数组对象的内容正在改变,因此数组变量实际上是最终变量,这是允许的:

代码语言:javascript
复制
public static IntUnaryOperator foo(int n) {
    int[] value = new int[] { n };
    return i -> value[0] += i;
}

任何具有可变字段的对象都可能被用作持卡器。正如下面@andersschuller所建议的,一个AtomicInteger非常适合这里,并使返回的函数线程安全:

代码语言:javascript
复制
public static IntUnaryOperator foo(int n) {
    AtomicInteger value = new AtomicInteger(n);
    return i -> value.addAndGet(i);
}

@srborlongan指出,可以使用更短的方法引用(尽管不是更易读的)重写它:

代码语言:javascript
复制
public static IntUnaryOperator foo(int n) {
    return new AtomicInteger(n)::addAndGet;
}
票数 8
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/24082945

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档