foreach用法_为什么不应该用Stream forEach替换for循环的3个原因

foreach用法

foreach用法

太棒了! 我们正在将代码库迁移到Java8。我们将用函数替换所有内容。 扔掉设计模式。 删除面向对象。 对! 我们走吧!

等一下

Java 8已经问世了一年多,而这种兴奋又回到了日常业务中。

baeldung.com从2015年5月开始执行的一项非代表性研究发现, 他们的读者中有38%的人已经采用Java 8 。 在此之前,Typsafe在2014年末进行的一项研究声称 ,其用户中Java 8的采用率为27% 。

这对您的代码库意味着什么?

某些Java 7-> Java 8迁移重构是理所当然的。 例如,将Callable传递给ExecutorService

ExecutorService s = ...

// Java 7 - meh...
Future<String> f = s.submit(
    new Callable<String>() {
        @Override
        public String call() {
            return "Hello World";
        }
    }
);

// Java 8 - of course!
Future<String> f = s.submit(() -> "Hello World");

匿名类样式实际上在这里没有添加任何值。

除了这些容易理解的话题之外,还有其他不太明显的话题。 例如,是否使用 外部迭代器还是内部迭代器。 另请参阅Neil Gafter于2007年发表的有关永恒主题的有趣读物: http ://gafter.blogspot.ch/2007/07/internal-versus-external-iterators.html

以下两个逻辑的结果相同

List<Integer> list = Arrays.asList(1, 2, 3);

// Old school
for (Integer i : list)
    System.out.println(i);

// "Modern"
list.forEach(System.out::println);

我主张“现代”方法应格外小心,即只有在您真正从内部功能迭代中受益时(例如,通过Stream的map()flatMap()和其他操作链接一组操作map() ,才应格外小心。

与经典方法相比,这是“现代”方法的缺点的简短列表:

1.绩效–您会因此而损失

Angelika Langer在她的文章以及 她在会议上发表的 相关演讲中已经很好地总结了这个主题:

https://jaxenter.com/java-performance-tutorial-how-fast-are-the-java-8-streams-118830.html

在许多情况下,性能并不重要,因此您不应该进行任何过早的优化-因此您可能会声称此参数本身并不是真正的参数。 但是在这种情况下,我会反驳这种态度,说Stream.forEach()与普通的for循环相比的开销是如此之大以至于默认情况下使用它只会在您所有的CPU上堆积很多无用的CPU周期应用。 如果仅根据循环样式的选择来谈论将CPU消耗增加10%-20%,那么我们所做的根本就是错误的。 是的–各个循环无关紧要,但是可以避免整个系统的负担。

这是Angelika在普通循环上的基准测试结果,在装箱的整数列表中找到最大值:

ArrayList, for-loop : 6.55 ms
ArrayList, seq. stream: 8.33 ms

在其他情况下,当我们对原始数据类型执行相对简单的计算时,我们绝对应该退回到经典的for循环(最好是数组而不是集合)。

这是Angelika在普通循环上的基准测试结果,在原始整数数组中找到最大值:

int-array, for-loop : 0.36 ms
int-array, seq. stream: 5.35 ms

过早的优化效果不好,但避免过早优化的货运教育更加糟糕。 重要的是要反思我们所处的环境,并在这种环境下做出正确的决定。 我们之前已经写过关于性能的博客,请参阅我们的文章 《 Java十大简单性能优化》

2.可读性–至少对于大多数人而言

我们是软件工程师。 我们将始终讨论我们的代码样式,就像它真的很重要一样。 例如,空格或花括号。

我们这样做的原因是因为软件维护很困难。 特别是别人编写的代码。 很久以前。 在切换到Java之前,谁可能只写了C代码。

当然,在到目前为止的示例中,我们确实没有可读性问题,这两个版本可能是等效的:

List<Integer> list = Arrays.asList(1, 2, 3);

// Old school
for (Integer i : list)
    System.out.println(i);

// "Modern"
list.forEach(System.out::println);

但是这里发生了什么:

List<Integer> list = Arrays.asList(1, 2, 3);

// Old school
for (Integer i : list)
    for (int j = 0; j < i; j++)
        System.out.println(i * j);

// "Modern"
list.forEach(i -> {
    IntStream.range(0, i).forEach(j -> {
        System.out.println(i * j);
    });
});

事情开始变得更加有趣和异常。 我不是说“更糟”。 这是实践和习惯的问题。 而且没有黑/白问题的答案。 但是,如果其余代码库是必须的(可能是这样),则嵌套范围声明和forEach()调用以及lambda肯定是不寻常的,这会在团队中引起 认知冲突。

您可以构建一些示例,其中命令式方法比等效的功能式方法感觉更尴尬,如此处所示:

但是在很多情况下,这是不正确的,并且要编写功能上相对简单的命令相当的命令相当困难(同样,效率低下)。 可以在此博客的先前文章中看到一个示例: http : //blog.jooq.org/2015/09/09/how-to-use-java-8-functional-programming-to-generate-an-alphabetic -顺序/

在那篇文章中,我们生成了一个字符序列:

A, B, ..., Z, AA, AB, ..., ZZ, AAA

…类似于MS Excel中的列:

图1_50047

命令式方法( 最初由Stack Overflow上的一个未命名用户使用):

import static java.lang.Math.*;
 
private static String getString(int n) {
    char[] buf = new char[(int) floor(log(25 * (n + 1)) / log(26))];
    for (int i = buf.length - 1; i >= 0; i--) {
        n--;
        buf[i] = (char) ('A' + n % 26);
        n /= 26;
    }
    return new String(buf);
}

……在简洁性上可能胜过功能性的:

import java.util.List;
 
import org.jooq.lambda.Seq;
 
public class Test {
    public static void main(String[] args) {
        int max = 3;
 
        List<String> alphabet = Seq
            .rangeClosed('A', 'Z')
            .map(Object::toString)
            .toList();
 
        Seq.rangeClosed(1, max)
           .flatMap(length ->
               Seq.rangeClosed(1, length - 1)
                  .foldLeft(Seq.seq(alphabet), (s, i) -> 
                      s.crossJoin(Seq.seq(alphabet))
                       .map(t -> t.v1 + t.v2)))
           .forEach(System.out::println);
    }
}

并且这已经在使用 jOOλ ,以简化功能Java的编写。

3.可维护性

让我们再次考虑前面的示例。 现在,我们不再对值相乘,而是对它们进行除法。

List<Integer> list = Arrays.asList(1, 2, 3);

// Old school
for (Integer i : list)
    for (int j = 0; j < i; j++)
        System.out.println(i / j);

// "Modern"
list.forEach(i -> {
    IntStream.range(0, i).forEach(j -> {
        System.out.println(i / j);
    });
});

显然,这是自找麻烦,我们可以在异常堆栈跟踪中立即看到问题。

老套

Exception in thread "main" java.lang.ArithmeticException: / by zero
	at Test.main(Test.java:13)

现代

Exception in thread "main" java.lang.ArithmeticException: / by zero
	at Test.lambda$1(Test.java:18)
	at java.util.stream.Streams$RangeIntSpliterator.forEachRemaining(Streams.java:110)
	at java.util.stream.IntPipeline$Head.forEach(IntPipeline.java:557)
	at Test.lambda$0(Test.java:17)
	at java.util.Arrays$ArrayList.forEach(Arrays.java:3880)
	at Test.main(Test.java:16)

哇。 我们只是…吗? 是。 这就是为什么我们首先在项目1中遇到性能问题的原因。 对于JVM和库,内部迭代只是要做很多工作。 这是一个非常简单的用例,我们可以用AA, AB, .., ZZ系列的产品展示同样的东西。

从维护的角度来看,函数式编程风格比命令式编程要困难得多,尤其是当您在传统代码中盲目地将两种风格混合在一起时。

结论

这通常是一个关于函数式编程,关于声明式编程的博客。 我们喜欢lambda。 我们喜欢SQL。 结合起来,它们可以创造奇迹。

但是,当您迁移到Java 8并打算在代码中使用更多功能的样式时,请注意FP并不总是总会更好-出于各种原因。 实际上,它从来没有“更好”,它只是不同而已,它使我们对问题有不同的推理。

我们的Java开发人员将需要进行练习,并对何时使用FP以及何时坚持使用OO /命令式有一个直观的了解。 通过适当的实践,将两者结合起来将有助于我们改善软件。

或者,用鲍伯叔叔的话来说:

底线就是这个。 当您知道OO编程是什么时,它就是好的。 当您知道函数式编程是什么时,它就是好的。 一旦了解了功能性OO编程,它也是不错的选择。

http://blog.cleancoder.com/uncle-bob/2014/11/24/FPvsOO.html

翻译自: https://www.javacodegeeks.com/2015/12/3-reasons-shouldnt-replace-loops-stream-foreach.html

foreach用法

cunhu4317
关注 关注
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
为什么不应该Stream.forEach()替换for循环的3个原因
06-26 860
这篇文章最初发表在jooq.org上 ,这是一个博客,从jOOQ的角度着眼于所有开源,Java和软件开发。 太棒了! 我们正在将代码库迁移到Java8。我们将用函数替换所有内容。 扔掉设计模式。 删除面向对象。 对! 我们走吧! 等一下 Java 8已经问世了一年多,而这种兴奋又回到了日常业务中。 baeldung.com从2015年5月开始执行的一项非代表性研究发现, 他们的读者...
Java8之Stream流代替For循环操作
08-24
主要介绍了Java8之Stream流代替For循环操作,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
【项目实战】‘stream().forEach()‘‘ 和 ‘forEach()‘的差别 ‘ (可能会改变语义)
最新发布
本本本添哥
08-21 1007
选择依据如果你需要利用 Stream API 的强大功能(如过滤、映射等),使用。如果你只是想遍历集合并执行一些操作,使用forEach()即可。性能考虑如果集合较大,使用 Stream API 可能会有更好的性能,特别是利用并行流。如果集合较小,直接使用forEach()可能更快,因为避免了 Stream API 的额外开销。
lambda 表达式 forEachstream.forEach 跳出循环
七点十七
06-14 706
Java8 lambda 表达式 forEach 提前终止循环 解决方案
Java8 Stream 流机制和 Lambda 表达式
hmyqwe的博客
04-08 351
一、Stream 流介绍与使用场景 Stream 流介绍 java8 中的stream 与InputStream和OutputStream是完全不同的概念, stream 是用于对集合迭代器的增强,使之完成能够完成更高效的聚合操作(过滤、排序、统计分组)或者大批量数据操作。 stream 与 Lambda 表达式结合后编码效率大大提高,可读性更强。 举例如下: // 获取所有红色苹果的总重量 appleStore.stream().filter(a -> "red".equals(a.getCol
jdk8特性例子 流 Streams
arkblue的专栏
02-15 1408
java.util.Stream represents a sequence of elements on which one or more operations can be performed. Stream operations are either intermediate or terminal. While terminal operations return a res
深入解析Jdk8中Stream流的使用让你脱离for循环
08-25
* flatMap:可用Stream替换值,然后将多个Stream连接成一个Stream,会将之前生成Stream流的每一个元素更换为一个新的Stream对象。 使用Stream流的好处 使用Stream流可以让开发者更方便地处理数据,例如,给你一个...
Stream API,将 for 循环改为 stream.forEach()。可以写一个demo吗
04-20
这个示例演示了如何使用Stream API的forEach()方法来替换for循环。在这个示例中,我们遍历了一个整数列表,并使用for循环forEach()方法打印每个数字。使用Stream API的forEach()方法可以更加简洁和直观地处理集合...
java程序中foreach用法示例
09-04
- **无法并行遍历**:foreach循环不能同时遍历两个或多个集合,若需并行操作,可以考虑使用Java 8的Stream API或其他并发处理工具。 **5. 操作限制** 在示例中提到,传统的迭代器(Iterator)允许在遍历过程中调用`...
stream foreach跳出循环
06-25
2. 将`forEach`替换为`forEachOrdered`,然后在适当的位置使用`return`语句: ```java numbers.stream() .forEachOrdered(i -> { if (i > 10) { return; // 结束当前迭代 } System.out.println(i); }); ``` ...
stream替代双层for循环
qq_43504447的博客
05-29 2976
这是在处理业务中遇到的: 数据如下: public class Book { private String bookId; private String name; private String depName; private String authDepName; public String getBookId() { return bookId; } public void setBookId(String bookId) { this.bookId = bookId;
java8的stream流处理使用例子
qq_21207803的博客
07-21 6658
java8的stream流处理使用例子。
Java8 Stream详解~遍历/匹配(foreach/find/match)
小强快跑~~
02-25 5126
Stream也是支持类似集合的遍历和匹配元素的,只是Stream中的元素是以Optional类型存在的。Stream的遍历、匹配非常简单。 // import已省略,请自行添加,后面代码亦是 public class StreamTest { public static void main(String[] args) { List<Integer> list = Arrays.asList(7, 6, 9, 3, 8, 2, 1); // 遍历输出
Java 8中 Stream 的小知识
zhaohuodian的博客
09-07 519
stream 到底是什么呢?官方的简短定义:“从支持数据处理操作的源生成的元素序列”元素序列:你可以简单将它类比于一样,不过集合说的是数据的集合,而 stream 重点在于表达计算。如我们之前说到的 filter、map、sorted、limit等等源:昨天我提到,如果了解过 Liunx 管道命令的朋友们,会知道,Liunx 的管道命令中的前一条命令的结果(输出流)就是执行下一条命令的输入流。
Java8 Stream新特性详解及实战
程序新视界
10-09 7974
Java8 Stream新特性详解及实战 背景介绍 在阅读Spring Boot源代码时,发现Java 8的新特性已经被广泛使用,如果再不学习Java8的新特性并灵活应用,你可能真的要out了。为此,针对Java8的新特性,会更新一系列的文章,欢迎大家持续关注。 首先,我们来看一下Spring Boot源代码ConfigFileApplicationListener类中的一段代码: private...
Java集合遍历方式(for循环stream()&forEach())比较
weixin_40903413的博客
12-23 7334
以上这些,我们可以做个总结了:+ 对于非方法引用 Lambda 表达式,编译器都会生成对应的 desugaring method;+ desugaring method 参数列表是接口方法参数列表加上变量捕获列表+ 变量捕获由虚拟机提供,是闭包访问变量的基础;
java--基础--27.2--Stream流--流的使用
zhou920786312的博客
07-19 107
1、介绍 1.1、整体API 1.2、测试数据 2、中间操作 2.1、filter筛选 通过使用filter方法进行条件筛选,filter的方法参数为一个条件 通过distinct方法快速去除重复的元素 通过limit方法指定返回流的个数,limit的参数值必须>=0,否则将会抛出异常 通过skip方法跳过流中的元素,上述例子跳过前两个元素 skip的参数值必须>=0,否则将会抛出异常所谓流映射就是将接受的元素映射成另外一个元素。 通过map方法可以完成映射,该例子完成中String -> Integ
Stream流中forEach方法
热门推荐
李长渊的博客
05-09 1万+
Stream流中forEach方法
写文章

热门文章

  • 手机nfc_如何在Android中编写NFC标签 2626
  • junit5_在Eclipse中有效使用JUnit 2218
  • 华为云计算_为什么要使用云计算? 的优点和缺点 1901
  • java并行查询数据库_使用Java 8处理并行数据库流 1868
  • 数据库查询错误null_为什么NULL是错误的? 1773

最新文章

  • 手机nfc_如何在Android中编写NFC标签
  • ObjectBox,一个现代且易于使用的Android数据库
  • gradle_在Android Studio和Gradle中使用Robolectric和Robotium
2021年49篇
2020年151篇

目录

目录

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值

玻璃钢生产厂家卡通雕塑玻璃钢生产厂家玻璃钢花盆生产可行性研究提供玻璃钢花盆厂家赤峰公园玻璃钢雕塑厂家玻璃钢艺术造型玻璃钢雕塑价格福建玻璃钢花盆批发滨州校园玻璃钢雕塑制作深圳市龙翔玻璃钢雕塑厂五家渠商场美陈深圳玻璃钢雕塑摆件价钱玻璃钢花盆工艺技术玻璃钢埃及雕塑赤峰市翁牛特旗玻璃钢动物雕塑淄博玻璃钢雕塑制作玻璃钢花盆地址玻璃钢雕塑哪里可以买到玻璃钢雕塑厂接单长治玻璃钢广场雕塑价格江苏人物玻璃钢雕塑设计玻璃钢卡通雕塑设计价格玻璃钢雕塑中标志性建筑揭阳玻璃钢卡通雕塑材质赣州玻璃钢雕塑多少钱关公玻璃钢雕塑制作厂家临汾玻璃钢气球雕塑玻璃钢孔子雕塑哪个品牌好沈阳玻璃钢梅花鹿雕塑惠州透明玻璃钢雕塑厂家户外玻璃钢雕塑定制玛雅玻璃钢雕塑香港通过《维护国家安全条例》两大学生合买彩票中奖一人不认账让美丽中国“从细节出发”19岁小伙救下5人后溺亡 多方发声单亲妈妈陷入热恋 14岁儿子报警汪小菲曝离婚始末遭遇山火的松茸之乡雅江山火三名扑火人员牺牲系谣言何赛飞追着代拍打萧美琴窜访捷克 外交部回应卫健委通报少年有偿捐血浆16次猝死手机成瘾是影响睡眠质量重要因素高校汽车撞人致3死16伤 司机系学生315晚会后胖东来又人满为患了小米汽车超级工厂正式揭幕中国拥有亿元资产的家庭达13.3万户周杰伦一审败诉网易男孩8年未见母亲被告知被遗忘许家印被限制高消费饲养员用铁锨驱打大熊猫被辞退男子被猫抓伤后确诊“猫抓病”特朗普无法缴纳4.54亿美元罚金倪萍分享减重40斤方法联合利华开始重组张家界的山上“长”满了韩国人?张立群任西安交通大学校长杨倩无缘巴黎奥运“重生之我在北大当嫡校长”黑马情侣提车了专访95后高颜值猪保姆考生莫言也上北大硕士复试名单了网友洛杉矶偶遇贾玲专家建议不必谈骨泥色变沉迷短剧的人就像掉进了杀猪盘奥巴马现身唐宁街 黑色着装引猜测七年后宇文玥被薅头发捞上岸事业单位女子向同事水杯投不明物质凯特王妃现身!外出购物视频曝光河南驻马店通报西平中学跳楼事件王树国卸任西安交大校长 师生送别恒大被罚41.75亿到底怎么缴男子被流浪猫绊倒 投喂者赔24万房客欠租失踪 房东直发愁西双版纳热带植物园回应蜉蝣大爆发钱人豪晒法院裁定实锤抄袭外国人感慨凌晨的中国很安全胖东来员工每周单休无小长假白宫:哈马斯三号人物被杀测试车高速逃费 小米:已补缴老人退休金被冒领16年 金额超20万

玻璃钢生产厂家 XML地图 TXT地图 虚拟主机 SEO 网站制作 网站优化