Idiomatic Collection iteration in Java 8
什么是Java 8中集合的惯用迭代,为什么?
1 2 3 4 5 |
或
1 2 3 4 5 |
在这个答案的注释线程中,用户bringer128在C中提到了关于类似问题的这些问题:好的。
foreach与someList.foreach()好的。
通用列表:foreach还是list.foreach?好的。
我建议不要将C语言的讨论应用到Java中。当然,讨论是有趣的,问题表面上是相似的。但是,Java和C语言是不同的语言,因此需要考虑不同的语言。好的。
例如,这个答案提到C
另一个例子来自这个答案,它提到在C中,由列表的
在任何情况下,不要阅读C语言的讨论,并假设类似的推理适用于Java。好的。
现在,来回答这个问题。-)好的。
我认为现在将一种风格声明为惯用或优于另一种风格还为时过早。Java 8刚刚发布,很少有人有这样的经验。lambda是新的和不熟悉的,这会让许多程序员感到不舒服。因此,他们会坚持他们的尝试和真正的循环。这很明智。不过,在几年后,当每个人都习惯了羔羊肉之后,for循环可能会变得明显过时。时间会证明一切。好的。
(我认为这发生在仿制药上。当他们还是新手的时候,他们很吓人,特别是野猫。然而,如今,非通用代码看起来明显过时,在我看来,它有一股霉味。)好的。
我很早就知道这会怎样。当然,我可能错了。好的。
我会说,对于计算固定的短循环,例如最初发布的问题:好的。
没关系。这可以改写为好的。
1 |
甚至好的。
1 |
但实际上,这段代码非常简单,很难说有一种方法明显更好。好的。
在某些情况下,天平会向一个或另一个方向倾斜。如果循环体可以抛出一个选中的异常,那么for循环显然更好。如果循环体是可插入的(例如,将
更新的示例,好的。
1 2 3 4 5 |
有点复杂,但只是稍微复杂一点。我不会用多行lambda来写这个:好的。
1 2 3 4 5 |
在我看来,这比直接for循环没有任何优势,lambda的不同语义是由第一行角上的小箭头表示的。然而,(类似于Bringer128的答案)我将把它从一个大的
1 2 3 |
我认为lambda/streams方法在这里开始显示出一点优势,但只是一点,因为这仍然是一个非常简单的例子。使用lambda/streams将一些条件控制逻辑替换为数据筛选操作。这可能对某些操作有意义,但对其他操作没有意义。好的。
随着事情变得越来越复杂,这两种方法之间的差别开始变得越来越明显。这些简单的例子很简单,很明显它们是做什么的。现实世界中的例子可能要复杂得多。考虑JDK的方法class.getEnclosingMethod中的代码(滚动到第1023-1052行):好的。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | Class<?> enclosingCandidate = enclosingInfo.getEnclosingClass(); // ... for(Method m: enclosingCandidate.getDeclaredMethods()) { if (m.getName().equals(enclosingInfo.getName()) ) { Class<?>[] candidateParamClasses = m.getParameterTypes(); if (candidateParamClasses.length == parameterClasses.length) { boolean matches = true; for(int i = 0; i < candidateParamClasses.length; i++) { if (!candidateParamClasses[i].equals(parameterClasses[i])) { matches = false; break; } } if (matches) { // finally, check return type if (m.getReturnType().equals(returnType) ) return m; } } } } throw new InternalError("Enclosing method not found"); |
(为了示例,省略了一些安全检查和注释。)好的。
这里我们有一对嵌套的for循环,其中有几个层次的条件逻辑和一个布尔标志。把这段代码通读一段时间,看看你是否能理解它的作用。好的。
使用lambda和流,可以如下重写此代码:好的。
1 2 3 4 5 6 | return Arrays.stream(enclosingInfo.getEnclosingClass().getDeclaredMethods()) .filter(m -> Objects.equals(m.getName(), enclosingInfo.getName())) .filter(m -> Arrays.equals(m.getParameterTypes(), parameterClasses)) .filter(m -> Objects.equals(m.getReturnType(), returnType)) .findFirst() .orElseThrow(() -> new InternalError("Enclosing method not found"); |
在经典版本中,循环控制和条件逻辑都是关于搜索数据结构中的匹配项。它有点扭曲,因为如果检测到不匹配,它会在内部循环的早期中断,但是如果找到匹配,它会在方法的早期返回。但是,一旦你盯着这段代码看足够长的时间,你就会发现它正在搜索符合一系列条件的第一个元素,并返回它;如果找不到,它就会抛出一个错误。一旦你意识到这一点,lambda/streams方法就会突然出现。它不仅短得多,而且更容易理解它在做什么。好的。
当然,也有一些循环会有奇怪的条件和副作用,不能轻易地转化为流。但是有很多for循环只是搜索数据结构、有条件地处理元素、返回第一个匹配项、累积匹配项集合或累积转换元素。这些操作自然会被改写成流,我敢说,是以惯用的方式。好的。好啊。
在通用idiomatic for the form is moreλ单环whereas the statement,不让更多的lambda -多语言意识的for循环。(这ignores泛函组合进入黑莓风格if possible)。P></
一个更多的风格你不值得一提:reference method is theP></
1 |
编辑:P></
当你寻找答案,你会发现更多的通用;因为,在lambda是在Java list.foreach method is used,the less在实践。P></
"我知道为什么在响应非λis for黑莓idiomatic多语言?"这是黑莓茶,逆向,多语言,语言中最idiomatic lambda are not。to be used for lambda趋势成分,我知道如果我从你的to take the example问题进入了它的功能和风格。P></
1 2 | // Thanks to @skiwi for fixing this code foos.stream().filter(foo -> bars.get(foo) != null).forEach(System.out::println); |
在the above example,using声明会多做努力的lambda easier Rather比读。P></
You should be using the New only if it / s的流list'
你会rewrite the following statement to,with which does make streams感:P></
1 2 3 |
This is a泛函的方法,我们将:P></
我在正规的话:黑莓P></