Which of the following is better practice in Java 8? 以下哪种是Java 8中的最佳实践?
Java 8: Java 8:
joins.forEach(join -> mIrc.join(mSession, join));
Java 7: Java 7:
for (String join : joins) {
mIrc.join(mSession, join);
}
I have lots of for loops that could be "simplified" with lambdas, but is there really any advantage of using them? 我有很多可以用lambda“简化”的for循环,但是使用它们真的有任何优势吗? Would it improve their performance and readability? 会提高其性能和可读性吗?
EDIT 编辑
I'll also extend this question to longer methods. 我还将这个问题扩展到更长的方法。 I know that you can't return or break the parent function from a lambda and this should also be taken into consideration when comparing them, but is there anything else to be considered? 我知道您无法从lambda返回或中断父函数,在比较它们时也应考虑到这一点,但是还有其他需要考虑的地方吗?
#1楼
参考:https://stackoom.com/question/17ncs/Java-Iterable-forEach-与foreach循环
#2楼
The advantage comes into account when the operations can be executed in parallel. 当可以并行执行操作时,将考虑到这一优势。 (See http://java.dzone.com/articles/devoxx-2012-java-8-lambda-and - the section about internal and external iteration) (请参阅http://java.dzone.com/articles/devoxx-2012-java-8-lambda-和 -有关内部和外部迭代的部分)
- The main advantage from my point of view is that the implementation of what is to be done within the loop can be defined without having to decide if it will be executed in parallel or sequential 从我的角度来看,主要优点是可以定义循环中要执行的操作,而不必决定是并行执行还是顺序执行
- If you want your loop to be executed in parallel you could simply write如果您希望并行执行循环,则只需编写
joins.parallelStream().forEach(join -> mIrc.join(mSession, join));
You will have to write some extra code for thread handling etc. 您将不得不编写一些额外的代码来进行线程处理等。
Note: For my answer I assumed joins implementing the java.util.Stream
interface. 注意:对于我的答案,我假设加入了实现java.util.Stream
接口的连接。 If joins implements only the java.util.Iterable
interface this is no longer true. 如果joins仅实现java.util.Iterable
接口,则不再适用。
#3楼
I feel that I need to extend my comment a bit... 我觉得我需要补充一点评论...
About paradigm\\style 关于范式\\样式
That's probably the most notable aspect. 这可能是最值得注意的方面。 FP became popular due to what you can get avoiding side-effects. FP之所以受欢迎,是因为您可以避免副作用。 I won't delve deep into what pros\\cons you can get from this, since this is not related to the question. 由于这与问题无关,因此我不会深入研究可从中获得哪些利弊。
However, I will say that the iteration using Iterable.forEach is inspired by FP and rather result of bringing more FP to Java (ironically, I'd say that there is no much use for forEach in pure FP, since it does nothing except introducing side-effects). 但是,我会说使用Iterable.forEach进行的迭代是受FP启发的,而是将更多FP引入Java的结果(具有讽刺意味的是,我想说在纯FP中forEach并没有太多用处,因为它除了引入之外什么也没有做副作用)。
In the end I would say that it is rather a matter of taste\\style\\paradigm you are currently writing in. 最后,我要说的是,这只是您当前正在编写的“品味\\样式\\范例”问题。
About parallelism. 关于并行性。
From performance point of view there is no promised notable benefits from using Iterable.forEach over foreach(...). 从性能的角度来看,与foreach(...)相比,使用Iterable.forEach不会带来任何明显的好处。
According to official docs on Iterable.forEach : 根据Iterable.forEach的官方文档 :
Performs the given action on the contents of the Iterable, in the order elements occur when iterating, until all elements have been processed or the action throws an exception. 对Iterable的内容执行给定的操作, 以迭代时元素出现的顺序 ,直到所有元素都已处理或该操作引发异常。
... ie docs pretty much clear that there will be no implicit parallelism. ...即文档非常清楚,不会存在隐式并行性。 Adding one would be LSP violation. 添加一个将违反LSP。
Now, there are "parallell collections" that are promised in Java 8, but to work with those you need to me more explicit and put some extra care to use them (see mschenk74's answer for example). 现在,有Java 8承诺的“并行集合”,但是要与我一起使用,您需要更加明确,并格外小心地使用它们(例如,请参阅mschenk74的答案)。
BTW: in this case Stream.forEach will be used, and it doesn't guarantee that actual work will be done in parallell (depends on underlying collection). 顺便说一句:在这种情况下,将使用Stream.forEach ,它不能保证实际工作将并行进行(取决于基础集合)。
UPDATE: might be not that obvious and a little stretched at a glance but there is another facet of style and readability perspective. 更新:可能不那么明显,乍一看有点张扬,但还有样式和可读性方面的另一个方面。
First of all - plain old forloops are plain and old. 首先-普通的旧forloop既普通又旧。 Everybody already knows them. 每个人都已经认识他们。
Second, and more important - you probably want to use Iterable.forEach only with one-liner lambdas. 其次,也是更重要的一点-您可能只想将Iterable.forEach与单层lambda一起使用。 If "body" gets heavier - they tend to be not-that readable. 如果“身体”变重-他们往往不那么可读。 You have 2 options from here - use inner classes (yuck) or use plain old forloop. 从这里有2个选项-使用内部类(yuck)或使用普通的旧forloop。 People often gets annoyed when they see the same things (iteratins over collections) being done various vays/styles in the same codebase, and this seems to be the case. 当人们在同一代码库中看到相同的事情(集合上的迭代器)时,常常会感到烦恼,这似乎是事实。
Again, this might or might not be an issue. 同样,这可能是问题,也可能不是问题。 Depends on people working on code. 取决于从事代码工作的人员。
#4楼
forEach()
can be implemented to be faster than for-each loop, because the iterable knows the best way to iterate its elements, as opposed to the standard iterator way. forEach()
可以比for-each循环更快地实现,因为与标准迭代器方法相反,可迭代器知道迭代其元素的最佳方法。 So the difference is loop internally or loop externally. 所以区别是内部循环或外部循环。
For example ArrayList.forEach(action)
may be simply implemented as 例如ArrayList.forEach(action)
可以简单地实现为
for(int i=0; i<size; i++)
action.accept(elements[i])
as opposed to the for-each loop which requires a lot of scaffolding 与for-each循环相反,后者需要大量的脚手架
Iterator iter = list.iterator();
while(iter.hasNext())
Object next = iter.next();
do something with `next`
However, we also need to account for two overhead costs by using forEach()
, one is making the lambda object, the other is invoking the lambda method. 但是,我们还需要通过使用forEach()
来考虑两个开销成本,一个是制作lambda对象,另一个是调用lambda方法。 They are probably not significant. 它们可能并不重要。
see also http://journal.stuffwithstuff.com/2013/01/13/iteration-inside-and-out/ for comparing internal/external iterations for different use cases. 另请参阅http://journal.stuffwithstuff.com/2013/01/13/iteration-inside-and-out/,以比较不同用例的内部/外部迭代。
#5楼
The better practice is to use for-each
. 更好的做法是使用for-each
。 Besides violating the Keep It Simple, Stupid principle, the new-fangled forEach()
has at least the following deficiencies: 除了违反“ 保持简单,愚蠢”的原则外,新创建的forEach()
至少还存在以下缺陷:
- Can't use non-final variables . 不能使用非最终变量 。 So, code like the following can't be turned into a forEach lambda: 因此,无法将以下代码转换为forEach lambda:
Object prev = null; for(Object curr : list) { if( prev != null ) foo(prev, curr); prev = curr; }
- Can't handle checked exceptions . 无法处理检查的异常 。 Lambdas aren't actually forbidden from throwing checked exceptions, but common functional interfaces like
Consumer
don't declare any. 实际上并未禁止Lambda引发检查异常,但是诸如Consumer
通用功能接口并未声明任何异常。 Therefore, any code that throws checked exceptions must wrap them intry-catch
orThrowables.propagate()
. 因此,任何引发检查异常的代码都必须将它们包装在try-catch
或Throwables.propagate()
。 But even if you do that, it's not always clear what happens to the thrown exception. 但是即使您这样做,也不总是总是清楚抛出的异常发生了什么。 It could get swallowed somewhere in the guts offorEach()
它可能会被forEach()
的内脏吞没。 - Limited flow-control . 有限的流量控制 。 A
return
in a lambda equals acontinue
in a for-each, but there is no equivalent to abreak
. lambda的return
等于for-for的continue
,但不等于break
。 It's also difficult to do things like return values, short circuit, or set flags (which would have alleviated things a bit, if it wasn't a violation of the no non-final variables rule). 执行返回值,短路或设置标志之类的事情也很困难(如果这不违反非非最终变量规则,则可能会有所减轻)。 "This is not just an optimization, but critical when you consider that some sequences (like reading the lines in a file) may have side-effects, or you may have an infinite sequence." “这不仅是一种优化,而且当您考虑某些序列(例如读取文件中的行)可能有副作用,或者您可能有一个无限序列时,这一点至关重要。” - Might execute in parallel , which is a horrible, horrible thing for all but the 0.1% of your code that needs to be optimized. 可能并行执行 ,这对于除了需要优化的代码的0.1%之外的所有代码来说都是一件可怕的事情。 Any parallel code has to be thought through (even if it doesn't use locks, volatiles, and other particularly nasty aspects of traditional multi-threaded execution). 任何并行代码都必须经过仔细考虑(即使它不使用锁,volatile和传统多线程执行的其他特别讨厌的方面)。 Any bug will be tough to find. 任何错误都很难找到。
- Might hurt performance , because the JIT can't optimize forEach()+lambda to the same extent as plain loops, especially now that lambdas are new. 可能会损害性能 ,因为JIT无法以与普通循环相同的程度优化forEach()+ lambda,尤其是现在lambda是新的。 By "optimization" I do not mean the overhead of calling lambdas (which is small), but to the sophisticated analysis and transformation that the modern JIT compiler performs on running code. “优化”不是指调用lambda(很小)的开销,而是指现代JIT编译器对正在运行的代码执行的复杂分析和转换。
- If you do need parallelism, it is probably much faster and not much more difficult to use an ExecutorService . 如果您确实需要并行性,则使用ExecutorService可能会更快,也不会更困难 。 Streams are both automagical (read: don't know much about your problem) and use a specialized (read: inefficient for the general case) parallelization strategy ( fork-join recursive decomposition ). 流既是自动的(阅读:对您的问题不太了解), 又使用专门的(阅读:在一般情况下效率不高)并行化策略( fork-join递归分解 )。
- Makes debugging more confusing , because of the nested call hierarchy and, god forbid, parallel execution. 由于嵌套的调用层次结构以及并行执行,这使调试更加混乱 。 The debugger may have issues displaying variables from the surrounding code, and things like step-through may not work as expected. 调试器可能在显示周围代码中的变量时遇到问题,并且逐步操作之类的操作可能无法按预期进行。
- Streams in general are more difficult to code, read, and debug . 通常,流很难编码,读取和调试 。 Actually, this is true of complex " fluent " APIs in general. 实际上,通常对于复杂的“ 流畅 ” API都是如此。 The combination of complex single statements, heavy use of generics, and lack of intermediate variables conspire to produce confusing error messages and frustrate debugging. 复杂的单个语句,泛型的大量使用以及缺少中间变量的组合共同产生了令人困惑的错误消息并挫败了调试工作。 Instead of "this method doesn't have an overload for type X" you get an error message closer to "somewhere you messed up the types, but we don't know where or how." 而不是“此方法对X类型没有重载”,您得到的错误消息更接近“在某种程度上弄乱了类型,但我们不知道在哪里或如何。” Similarly, you can't step through and examine things in a debugger as easily as when the code is broken into multiple statements, and intermediate values are saved to variables. 同样,您无法像将代码分解为多个语句并将中间值保存到变量中一样轻松地在调试器中单步检查所有内容。 Finally, reading the code and understanding the types and behavior at each stage of execution may be non-trivial. 最后,阅读代码并理解每个执行阶段的类型和行为可能并非易事。
- Sticks out like a sore thumb . 伸出来就像一个酸痛的拇指 。 The Java language already has the for-each statement. Java语言已经具有for-each语句。 Why replace it with a function call? 为什么用函数调用替换它? Why encourage hiding side-effects somewhere in expressions? 为什么鼓励在表达式中的某处隐藏副作用? Why encourage unwieldy one-liners? 为什么鼓励笨拙的单线? Mixing regular for-each and new forEach willy-nilly is bad style. 将常规的for-each和new forEach混为一谈是不好的方式。 Code should speak in idioms (patterns that are quick to comprehend due to their repetition), and the fewer idioms are used the clearer the code is and less time is spent deciding which idiom to use (a big time-drain for perfectionists like myself!). 代码应该以习惯用语(由于重复而易于理解的模式)来表达,使用的习惯用语越少,代码就越清晰,决定使用哪种习惯用语的时间就越少(像我这样的完美主义者会浪费很多时间! )。
As you can see, I'm not a big fan of the forEach() except in cases when it makes sense. 如您所见,我不喜欢forEach(),除非有必要。
Particularly offensive to me is the fact that Stream
does not implement Iterable
(despite actually having method iterator
) and cannot be used in a for-each, only with a forEach(). 对我来说特别令人反感的是, Stream
没有实现Iterable
(尽管实际上具有方法iterator
),并且不能仅通过forEach()在for-each中使用。 I recommend casting Streams into Iterables with (Iterable<T>)stream::iterator
. 我建议使用(Iterable<T>)stream::iterator
将Streams转换为Iterables。 A better alternative is to use StreamEx which fixes a number of Stream API problems, including implementing Iterable
. 更好的选择是使用StreamEx ,它解决了许多Stream API问题,包括实现Iterable
。
That said, forEach()
is useful for the following: 也就是说, forEach()
对于以下各项很有用:
- Atomically iterating over a synchronized list . 以原子方式对同步列表进行迭代 。 Prior to this, a list generated with
Collections.synchronizedList()
was atomic with respect to things like get or set, but was not thread-safe when iterating. 在此之前,对于诸如get或set之类的东西,用Collections.synchronizedList()
生成的列表是原子的,但是在迭代时不是线程安全的。 - Parallel execution (using an appropriate parallel stream) . 并行执行(使用适当的并行流) 。 This saves you a few lines of code vs using an ExecutorService, if your problem matches the performance assumptions built into Streams and Spliterators. 如果您的问题与Streams和Spliterators中内置的性能假设相符,则与使用ExecutorService相比,这可以节省几行代码。
- Specific containers which , like the synchronized list, benefit from being in control of iteration (although this is largely theoretical unless people can bring up more examples) 特定容器 (如同步列表)受益于对迭代的控制(尽管这在很大程度上是理论上的,除非人们能提出更多示例)
- Calling a single function more cleanly by using
forEach()
and a method reference argument (ie,list.forEach (obj::someMethod)
). 通过使用forEach()
和方法引用参数(即list.forEach (obj::someMethod)
), 可以更清晰地调用单个函数 。 However, keep in mind the points on checked exceptions, more difficult debugging, and reducing the number of idioms you use when writing code. 但是,请记住检查异常的要点,更困难的调试以及减少编写代码时使用的惯用法数量。
Articles I used for reference: 我参考的文章:
- Everything about Java 8 关于Java 8的一切
- Iteration Inside and Out (as pointed out by another poster) 内外迭代 (另一位海报指出)
EDIT: Looks like some of the original proposals for lambdas (such as http://www.javac.info/closures-v06a.html ) solved some of the issues I mentioned (while adding their own complications, of course). 编辑:看起来像一些针对lambda的原始建议(例如http://www.javac.info/closures-v06a.html )解决了我提到的一些问题(当然,同时增加了它们的复杂性)。
#6楼
When reading this question one can get the impression, that Iterable#forEach
in combination with lambda expressions is a shortcut/replacement for writing a traditional for-each loop. 阅读此问题时,您可能会觉得, Iterable#forEach
与lambda表达式组合是编写传统的for-each循环的快捷方式/替代方法。 This is simply not true. 这是不正确的。 This code from the OP: 该代码来自OP:
joins.forEach(join -> mIrc.join(mSession, join));
is not intended as a shortcut for writing 不能用作写作的捷径
for (String join : joins) {
mIrc.join(mSession, join);
}
and should certainly not be used in this way. 并且当然不应以这种方式使用。 Instead it is intended as a shortcut (although it is not exactly the same) for writing 相反,它旨在用作编写的快捷方式(尽管并不完全相同)
joins.forEach(new Consumer<T>() {
@Override
public void accept(T join) {
mIrc.join(mSession, join);
}
});
And it is as a replacement for the following Java 7 code: 它是以下Java 7代码的替代品:
final Consumer<T> c = new Consumer<T>() {
@Override
public void accept(T join) {
mIrc.join(mSession, join);
}
};
for (T t : joins) {
c.accept(t);
}
Replacing the body of a loop with a functional interface, as in the examples above, makes your code more explicit: You are saying that (1) the body of the loop does not affect the surrounding code and control flow, and (2) the body of the loop may be replaced with a different implementation of the function, without affecting the surrounding code. 如上例所示,使用功能性接口替换循环的主体使您的代码更明确:您要说的是:(1)循环的主体不影响周围的代码和控制流,并且(2)循环主体可以用该函数的其他实现替换,而不会影响周围的代码。 Not being able to access non final variables of the outer scope is not a deficit of functions/lambdas, it is a feature that distinguishes the semantics of Iterable#forEach
from the semantics of a traditional for-each loop. 无法访问外部作用域的非最终变量并不是函数/ lambda的不足,它是一种功能 ,将Iterable#forEach
的语义与传统的for-each循环的语义区分开。 Once one gets used to the syntax of Iterable#forEach
, it makes the code more readable, because you immediately get this additional information about the code. 一旦习惯了Iterable#forEach
的语法,它就会使代码更具可读性,因为您会立即获得有关代码的其他信息。
Traditional for-each loops will certainly stay good practice (to avoid the overused term " best practice ") in Java. 传统的for-each循环肯定会保留Java中的优良作法 (以避免过度使用术语“ 最佳实践 ”)。 But this doesn't mean, that Iterable#forEach
should be considered bad practice or bad style. 但这并不意味着应将Iterable#forEach
视为不良做法或不良风格。 It is always good practice, to use the right tool for doing the job, and this includes mixing traditional for-each loops with Iterable#forEach
, where it makes sense. 使用正确的工具完成工作始终是一种好习惯,其中包括将传统的for-each循环与Iterable#forEach
混合Iterable#forEach
,这是有意义的。
Since the downsides of Iterable#forEach
have already been discussed in this thread, here are some reasons, why you might probably want to use Iterable#forEach
: 由于在该线程中已经讨论了Iterable#forEach
的缺点,因此有一些原因,为什么您可能想要使用Iterable#forEach
:
- To make your code more explicit: As described above,
Iterable#forEach
can make your code more explicit and readable in some situations. 为了使你的代码更明确:如上所述,Iterable#forEach
可以使代码更清晰易读在某些情况下。 - To make your code more extensible and maintainable: Using a function as the body of a loop allows you to replace this function with different implementations (see Strategy Pattern ).要使您的代码更具可扩展性和可维护性:将函数用作循环的主体使您可以用不同的实现替换此函数(请参阅策略模式 )。You could eg easily replace the lambda expression with a method call, that may be overwritten by sub-classes:例如,您可以轻松地用方法调用替换lambda表达式,该方法调用可能会被子类覆盖:
joins.forEach(getJoinStrategy());
Then you could provide default strategies using an enum, that implements the functional interface. 然后,您可以使用枚举提供默认策略,该枚举实现功能接口。 This not only makes your code more extensible, it also increases maintainability because it decouples the loop implementation from the loop declaration. 这不仅使您的代码更具可扩展性,而且还提高了可维护性,因为它使循环实现与循环声明脱钩。
- To make your code more debuggable: Seperating the loop implementation from the declaration can also make debugging more easy, because you could have a specialized debug implementation, that prints out debug messages, without the need to clutter your main code with
if(DEBUG)System.out.println()
. 使您的代码更易于调试:将循环实现与声明分开,还可以使调试更加容易,因为您可以使用专门的调试实现来打印调试消息,而无需使用if(DEBUG)System.out.println()
使您的主代码混乱if(DEBUG)System.out.println()
。 The debug implementation could eg be a delegate , that decorates the actual function implementation. 调试实现可以例如是装饰实际功能实现的委托 。 - To optimize performance-critical code: Contrary to some of the assertions in this thread,
Iterable#forEach
does already provide better performance than a traditional for-each loop, at least when using ArrayList and running Hotspot in "-client" mode.为了优化性能关键代码:相反,一些在这个线程的断言,Iterable#forEach
并已经提供了比更好的性能传统的for-each循环,至少使用ArrayList和在“-client”模式下运行热点时。While this performance boost is small and negligible for most use cases, there are situations, where this extra performance can make a difference.尽管对于大多数用例而言,这种性能提升很小并且可以忽略不计,但是在某些情况下,这种额外的性能可能会有所作为。Eg library maintainers will certainly want to evaluate, if some of their existing loop implementations should be replaced withIterable#forEach
.例如,如果应将某些现有循环实现替换为Iterable#forEach
,则例如,库维护人员当然会希望进行评估。
To back this statement up with facts, I have done some micro-benchmarks with Caliper .为了支持这一事实,我使用Caliper做了一些微基准测试。Here is the test code (latest Caliper from git is needed):这是测试代码(需要git的最新Caliper):
@VmOptions("-server") public class Java8IterationBenchmarks { public static class TestObject { public int result; } public @Param({"100", "10000"}) int elementCount; ArrayList<TestObject> list; TestObject[] array; @BeforeExperiment public void setup(){ list = new ArrayList<>(elementCount); for (int i = 0; i < elementCount; i++) { list.add(new TestObject()); } array = list.toArray(new TestObject[list.size()]); } @Benchmark public void timeTraditionalForEach(int reps){ for (int i = 0; i < reps; i++) { for (TestObject t : list) { t.result++; } } return; } @Benchmark public void timeForEachAnonymousClass(int reps){ for (int i = 0; i < reps; i++) { list.forEach(new Consumer<TestObject>() { @Override public void accept(TestObject t) { t.result++; } }); } return; } @Benchmark public void timeForEachLambda(int reps){ for (int i = 0; i < reps; i++) { list.forEach(t -> t.result++); } return; } @Benchmark public void timeForEachOverArray(int reps){ for (int i = 0; i < reps; i++) { for (TestObject t : array) { t.result++; } } } }
And here are the results: 结果如下:
When running with "-client", Iterable#forEach
outperforms the traditional for loop over an ArrayList, but is still slower than directly iterating over an array. 当使用“ -client”运行时, Iterable#forEach
优于通过ArrayList进行的传统for循环,但仍比直接通过数组进行迭代慢。 When running with "-server", the performance of all approaches is about the same. 当使用“-服务器”运行时,所有方法的性能大致相同。
- To provide optional support for parallel execution: It has already been said here, that the possibility to execute the functional interface of
Iterable#forEach
in parallel using streams , is certainly an important aspect.为并行执行提供可选的支持:在这里已经说过,使用流并行执行Iterable#forEach
功能接口的可能性无疑是一个重要方面。SinceCollection#parallelStream()
does not guarantee, that the loop is actually executed in parallel, one must consider this an optional feature.由于Collection#parallelStream()
不保证循环实际上是并行执行的,因此必须将其视为一项可选功能。By iterating over your list withlist.parallelStream().forEach(...);
通过使用list.parallelStream().forEach(...);
遍历您的列表list.parallelStream().forEach(...);
, you explicitly say: This loop supports parallel execution, but it does not depend on it.,您明确地说:该循环支持并行执行,但并不依赖于此。Again, this is a feature and not a deficit!同样,这是一个功能,而不是缺点!
By moving the decision for parallel execution away from your actual loop implementation, you allow optional optimization of your code, without affecting the code itself, which is a good thing.通过将并行执行的决策从实际的循环实现中移开,可以对代码进行可选的优化,而又不影响代码本身,这是一件好事。Also, if the default parallel stream implementation does not fit your needs, no one is preventing you from providing your own implementation.另外,如果默认的并行流实现不符合您的需求,那么没有人会阻止您提供自己的实现。You could eg provide an optimized collection depending on the underlying operating system, on the size of the collection, on the number of cores, and on some preference settings:例如,您可以根据基础操作系统,集合的大小,内核数以及某些首选项设置来提供优化的集合:
public abstract class MyOptimizedCollection<E> implements Collection<E>{ private enum OperatingSystem{ LINUX, WINDOWS, ANDROID } private OperatingSystem operatingSystem = OperatingSystem.WINDOWS; private int numberOfCores = Runtime.getRuntime().availableProcessors(); private Collection<E> delegate; @Override public Stream<E> parallelStream() { if (!System.getProperty("parallelSupport").equals("true")) { return this.delegate.stream(); } switch (operatingSystem) { case WINDOWS: if (numberOfCores > 3 && delegate.size() > 10000) { return this.delegate.parallelStream(); }else{ return this.delegate.stream(); } case LINUX: return SomeVerySpecialStreamImplementation.stream(this.delegate.spliterator()); case ANDROID: default: return this.delegate.stream(); } } }
The nice thing here is, that your loop implementation doesn't need to know or care about these details. 这里的好处是,您的循环实现无需了解或关心这些细节。