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/
我有一个Ruby程序,它使用rubyzip压缩XML文件的目录树。gem。我的问题是文件开始变得很重,我想提高压缩级别,因为压缩时间不是问题。我在rubyzipdocumentation中找不到一种为创建的ZIP文件指定压缩级别的方法。有人知道如何更改此设置吗?是否有另一个允许指定压缩级别的Ruby库? 最佳答案 这是我通过查看rubyzip内部创建的代码。level=Zlib::BEST_COMPRESSIONZip::ZipOutputStream.open(zip_file)do|zip|Dir.glob("**/*")d
很好奇,就使用rubyonrails自动化单元测试而言,你们正在做什么?您是否创建了一个脚本来在cron中运行rake作业并将结果邮寄给您?git中的预提交Hook?只是手动调用?我完全理解测试,但想知道在错误发生之前捕获错误的最佳实践是什么。让我们理所当然地认为测试本身是完美无缺的,并且可以正常工作。下一步是什么以确保他们在正确的时间将可能有害的结果传达给您? 最佳答案 不确定您到底想听什么,但是有几个级别的自动代码库控制:在处理某项功能时,您可以使用类似autotest的内容获得关于哪些有效,哪些无效的即时反馈。要确保您的提
我正在编写一个包含C扩展的gem。通常当我写一个gem时,我会遵循TDD的过程,我会写一个失败的规范,然后处理代码直到它通过,等等......在“ext/mygem/mygem.c”中我的C扩展和在gemspec的“扩展”中配置的有效extconf.rb,如何运行我的规范并仍然加载我的C扩展?当我更改C代码时,我需要采取哪些步骤来重新编译代码?这可能是个愚蠢的问题,但是从我的gem的开发源代码树中输入“bundleinstall”不会构建任何native扩展。当我手动运行rubyext/mygem/extconf.rb时,我确实得到了一个Makefile(在整个项目的根目录中),然后当
我有一个围绕一些对象的包装类,我想将这些对象用作散列中的键。包装对象和解包装对象应映射到相同的键。一个简单的例子是这样的:classAattr_reader:xdefinitialize(inner)@inner=innerenddefx;@inner.x;enddef==(other)@inner.x==other.xendenda=A.new(o)#oisjustanyobjectthatallowso.xb=A.new(o)h={a=>5}ph[a]#5ph[b]#nil,shouldbe5ph[o]#nil,shouldbe5我试过==、===、eq?并散列所有无济于事。
在MRIRuby中我可以这样做:deftransferinternal_server=self.init_serverpid=forkdointernal_server.runend#Maketheserverprocessrunindependently.Process.detach(pid)internal_client=self.init_client#Dootherstuffwithconnectingtointernal_server...internal_client.post('somedata')ensure#KillserverProcess.kill('KILL',
我有一些Ruby代码,如下所示:Something.createdo|x|x.foo=barend我想编写一个测试,它使用double代替block参数x,这样我就可以调用:x_double.should_receive(:foo).with("whatever").这可能吗? 最佳答案 specify'something'dox=doublex.should_receive(:foo=).with("whatever")Something.should_receive(:create).and_yield(x)#callthere
我正在编写一个小脚本来定位aws存储桶中的特定文件,并创建一个临时验证的url以发送给同事。(理想情况下,这将创建类似于在控制台上右键单击存储桶中的文件并复制链接地址的结果)。我研究过回形针,它似乎不符合这个标准,但我可能只是不知道它的全部功能。我尝试了以下方法:defauthenticated_url(file_name,bucket)AWS::S3::S3Object.url_for(file_name,bucket,:secure=>true,:expires=>20*60)end产生这种类型的结果:...-1.amazonaws.com/file_path/file.zip.A
Sinatra新手;我正在运行一些rspec测试,但在日志中收到了一堆不需要的噪音。如何消除日志中过多的噪音?我仔细检查了环境是否设置为:test,这意味着记录器级别应设置为WARN而不是DEBUG。spec_helper:require"./app"require"sinatra"require"rspec"require"rack/test"require"database_cleaner"require"factory_girl"set:environment,:testFactoryGirl.definition_file_paths=%w{./factories./test/
我真的很习惯使用Ruby编写以下代码:my_hash={}my_hash['test']=1Java中对应的数据结构是什么? 最佳答案 HashMapmap=newHashMap();map.put("test",1);我假设? 关于java-等价于Java中的RubyHash,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.com/questions/22737685/
我遵循MichaelHartl的“RubyonRails教程:学习Web开发”,并创建了检查用户名和电子邮件长度有效性的测试(名称最多50个字符,电子邮件最多255个字符)。test/helpers/application_helper_test.rb的内容是:require'test_helper'classApplicationHelperTest在运行bundleexecraketest时,所有测试都通过了,但我看到以下消息在最后被标记为错误:ERROR["test_full_title_helper",ApplicationHelperTest,1.820016791]test