保罗·格雷厄姆( Paul )在他的伟大文章“书呆子的复仇”(书呆子的复仇)中声称,语言在权力上各不相同。他提到了一个很好的练习--写了一个累加器生成器:
我们想要写一个函数来生成累加器--一个函数,它接受一个数字n,并返回一个函数,这个函数接受另一个数字i,并返回n个递增的i。
Java的解决方案是
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解决方案进行比较
def foo(n) {
return {n += it}
}
def accumulator = foo(1)
assert accumulator(2) == 3
assert accumulator(3) == 6发布于 2014-06-06 13:35:42
首先,您仍然可以使用匿名类语法而不是lambda语法使用所有新的Java 8接口。例如:
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。这个限制意味着您不能轻松地编写一个变量,其值在调用之间累积。以下内容不起作用:
public static IntUnaryOperator foo(int n) {
return i -> n += i; // nope, sorry!
}我们可以通过使用某个可变对象作为当前累加器值的持卡器来解决这个限制。为此可以使用一个单元素数组。数组变量没有变化,只有它指向的数组对象的内容正在改变,因此数组变量实际上是最终变量,这是允许的:
public static IntUnaryOperator foo(int n) {
int[] value = new int[] { n };
return i -> value[0] += i;
}任何具有可变字段的对象都可能被用作持卡器。正如下面@andersschuller所建议的,一个AtomicInteger非常适合这里,并使返回的函数线程安全:
public static IntUnaryOperator foo(int n) {
AtomicInteger value = new AtomicInteger(n);
return i -> value.addAndGet(i);
}@srborlongan指出,可以使用更短的方法引用(尽管不是更易读的)重写它:
public static IntUnaryOperator foo(int n) {
return new AtomicInteger(n)::addAndGet;
}https://stackoverflow.com/questions/24082945
复制相似问题