假设我有这份水果 list :-
List<String> f = Arrays.asList("Banana", "Apple", "Grape", "Orange", "Kiwi");
我需要为每个水果添加一个序列号并打印出来。水果或序列号的顺序无关紧要。所以这是一个有效的输出:-
4. Kiwi
3. Orange
1. Grape
2. Apple
5. Banana
解决方案#1
AtomicInteger number = new AtomicInteger(0);
String result = f.parallelStream()
.map(i -> String.format("%d. %s", number.incrementAndGet(), i))
.collect(Collectors.joining("\n"));
解决方案 #2
String result = IntStream.rangeClosed(1, f.size())
.parallel()
.mapToObj(i -> String.format("%d. %s", i, f.get(i - 1)))
.collect(Collectors.joining("\n"));
问题
为什么解决方案 1 是不好的做法?我在很多地方都看到基于 AtomicInteger 的解决方案很糟糕(比如 this answer ),特别是在并行流处理中(这就是我在上面使用并行流的原因,试图遇到问题) .
我看了这些问题/答案:-
In which cases Stream operations should be stateful?
Is use of AtomicInteger for indexing in Stream a legit way?
Java 8: Preferred way to count iterations of a lambda?
他们只是提到(除非我遗漏了什么)“可能会出现意想不到的结果”。像什么?在这个例子中会发生吗?如果没有,您能否提供一个可能发生的示例?
至于“不保证应用映射器函数的顺序”,好吧,这是并行处理的本质,所以我接受它,而且顺序不在此特定示例中很重要。
AtomicInteger 是线程安全的,因此在并行处理中应该不是问题。
有人可以举例说明在使用这种基于状态的解决方案时会出现哪些问题吗?
最佳答案
好吧,看看 Stuart Marks 的回答是什么 here - 他正在使用有状态谓词。
这是一些潜在的问题,但如果您不关心它们或真正理解它们 - 您应该没问题。
首先是顺序,在并行处理的当前实现下展示,但如果您不关心顺序,就像在您的示例中一样,就可以了。
第二个是潜在速度 AtomicInteger 递增一个简单的 int 会慢很多倍,如前所述,如果您关心这一点。
第三个更微妙。有时根本无法保证 map 会被执行,例如 java-9:
someStream.map(i -> /* do something with i and numbers */)
.count();
这里的重点是因为你是在计数,所以不需要做映射,所以跳过了。一般来说,命中某些中间操作的元素不能保证到达终端。想象一个 map.filter.map 的情况,第一个 map 可能比第二个 map “看到”更多的元素,因为一些元素可能被过滤了。所以不建议依赖这个,除非你能准确地推断出发生了什么。
在你的例子中,IMO,你做你做的事是非常安全的;但是如果你稍微改变了你的代码,这需要额外的推理来证明它的正确性。我会选择解决方案 2,只是因为它对我来说更容易理解,而且它没有上面列出的潜在问题。
关于java - 为什么不推荐基于 AtomicInteger 的 Stream 解决方案?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53329809/
类classAprivatedeffooputs:fooendpublicdefbarputs:barendprivatedefzimputs:zimendprotecteddefdibputs:dibendendA的实例a=A.new测试a.foorescueputs:faila.barrescueputs:faila.zimrescueputs:faila.dibrescueputs:faila.gazrescueputs:fail测试输出failbarfailfailfail.发送测试[:foo,:bar,:zim,:dib,:gaz].each{|m|a.send(m)resc
为什么4.1%2返回0.0999999999999996?但是4.2%2==0.2。 最佳答案 参见此处:WhatEveryProgrammerShouldKnowAboutFloating-PointArithmetic实数是无限的。计算机使用的位数有限(今天是32位、64位)。因此计算机进行的浮点运算不能代表所有的实数。0.1是这些数字之一。请注意,这不是与Ruby相关的问题,而是与所有编程语言相关的问题,因为它来自计算机表示实数的方式。 关于ruby-为什么4.1%2使用Ruby返
在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中的nil对象上调用方法,则会出现NoMethodError异常并显示消息:"undefinedmethod‘...’fornil:NilClass"然而,有一个tryRails中的方法,如果它被发送到一个nil对象,它只返回nil:require'rubygems'require'active_support/all'nil.try(:nonexisting_method)#noNoMethodErrorexceptionanymore那么try如何在内部工作以防止该异常? 最佳答案 像Ruby中的所有其他对象
关闭。这个问题需要detailsorclarity.它目前不接受答案。想改进这个问题吗?通过editingthispost添加细节并澄清问题.关闭8年前。Improvethisquestion为什么SecureRandom.uuid创建一个唯一的字符串?SecureRandom.uuid#=>"35cb4e30-54e1-49f9-b5ce-4134799eb2c0"SecureRandom.uuid方法创建的字符串从不重复?
我真的很习惯使用Ruby编写以下代码:my_hash={}my_hash['test']=1Java中对应的数据结构是什么? 最佳答案 HashMapmap=newHashMap();map.put("test",1);我假设? 关于java-等价于Java中的RubyHash,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.com/questions/22737685/
我刚刚被困在这个问题上一段时间了。以这个基地为例:moduleTopclassTestendmoduleFooendend稍后,我可以通过这样做在Foo中定义扩展Test的类:moduleTopmoduleFooclassSomeTest但是,如果我尝试通过使用::指定模块来最小化缩进:moduleTop::FooclassFailure这失败了:NameError:uninitializedconstantTop::Foo::Test这是一个错误,还是仅仅是Ruby解析变量名的方式的逻辑结果? 最佳答案 Isthisabug,or
这里有一个很好的答案解释了如何在Ruby中下载文件而不将其加载到内存中:https://stackoverflow.com/a/29743394/4852737require'open-uri'download=open('http://example.com/image.png')IO.copy_stream(download,'~/image.png')我如何验证下载文件的IO.copy_stream调用是否真的成功——这意味着下载的文件与我打算下载的文件完全相同,而不是下载一半的损坏文件?documentation说IO.copy_stream返回它复制的字节数,但是当我还没有下
我正在学习如何在我的Ruby代码中使用Module.prepend而不是alias_method_chain,我注意到有些人使用send调用它(example):ActionView::TemplateRenderer.send(:prepend,ActionViewTemplateRendererWithCurrentTemplate)而其他人直接调用它(example):ActionView::TemplateRenderer.prepend(ActionViewTemplateRendererWithCurrentTemplate)而且,虽然我还没有看到任何人使用这种风格,但我从
我在用Ruby执行简单任务时遇到了一件奇怪的事情。我只想用每个方法迭代字母表,但迭代在执行中先进行:alfawit=("a".."z")puts"That'sanalphabet:\n\n#{alfawit.each{|litera|putslitera}}"这段代码的结果是:(缩写)abc⋮xyzThat'sanalphabet:a..z知道为什么它会这样工作或者我做错了什么吗?提前致谢。 最佳答案 因为您的each调用被插入到在固定字符串之前执行的字符串文字中。此外,each返回一个Enumerable,实际上您甚至打印它。试试