gpt4 book ai didi

java - 累加器生成器测试 - Java 8

转载 作者:塔克拉玛干 更新时间:2023-11-03 04:20:27 25 4
gpt4 key购买 nike

Paul Graham,在他的精彩文章中 Revenge of the Nerds , 声称语言的力量各不相同。他提到了一个很好的练习——编写一个累加器生成器:

We want to write a function that generates accumulators-- a function that takes a number n, and returns a function that takes another number i and returns n incremented by 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)中已经有一些优雅的方式来编写类似于 Groovy 的代码,请参见下文。我试过 Function<Integer, Integer>

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

local variables referenced from a lambda expression must be final or effectively final

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

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

def foo(n) {
return {n += it}
}

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

最佳答案

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

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 ,因为它允许使用原始 int 而不是盒装 Integer 。如果合法的话,它在逻辑上等同于 Function<int,int> 。)

现在,我们如何使用 lambda 语法缩短这个笨重的东西?传递给 lambda 的局部变量必须(有效地)final .该限制意味着您不能简单地编写一个其值在调用之间累积的变量。以下内容有效:

public static IntUnaryOperator foo(int n) {
return i -> n += i; // nope, sorry!
}

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

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

关于java - 累加器生成器测试 - Java 8,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24082945/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com