Java 业务开发常见错误 100 例
朱晔
贝壳金服资深架构师
51940 人已学习
新⼈⾸单¥59
登录后,你可以任选4讲全文学习
课程目录
已完结/共 48 讲
代码篇 (23讲)
Java 业务开发常见错误 100 例
15
15
1.0x
00:00/00:00
登录|注册

31 | 加餐1:带你吃透课程中Java 8的那些重要知识点(一)

你好,我是朱晔。
Java 8 是目前最常用的 JDK 版本,在增强代码可读性、简化代码方面,相比 Java 7 增加了很多功能,比如 Lambda、Stream 流操作、并行流(ParallelStream)、Optional 可空类型、新日期时间类型等。
这个课程中的所有案例,都充分使用了 Java 8 的各种特性来简化代码。这也就意味着,如果你不了解这些特性的话,理解课程内的 Demo 可能会有些困难。因此,我将这些特性,单独拎了出来组成了两篇加餐。由于后面有单独一节课去讲 Java 8 的日期时间类型,所以这里就不赘述了。

如何在项目中用上 Lambda 表达式和 Stream 操作?

Java 8 的特性有很多,除了这两篇加餐外,我再给你推荐一本全面介绍 Java 8 的书,叫《Java 实战(第二版)》。此外,有同学在留言区问,怎么把 Lambda 表达式和 Stream 操作运用到项目中。其实,业务代码中可以使用这些特性的地方有很多。
这里,为了帮助你学习,并把这些特性用到业务开发中,我有三个小建议。
第一,从 List 的操作开始,先尝试把遍历 List 来筛选数据和转换数据的操作,使用 Stream 的 filter 和 map 实现,这是 Stream 最常用、最基本的两个 API。你可以重点看看接下来两节的内容来入门。
确认放弃笔记?
放弃后所记笔记将不保留。
新功能上线,你的历史笔记已初始化为私密笔记,是否一键批量公开?
批量公开的笔记不会为你同步至部落
公开
同步至部落
取消
完成
0/2000
荧光笔
直线
曲线
笔记
复制
AI
  • 深入了解
  • 翻译
    • 英语
    • 中文简体
    • 中文繁体
    • 法语
    • 德语
    • 日语
    • 韩语
    • 俄语
    • 西班牙语
    • 阿拉伯语
  • 解释
  • 总结
仅可试看部分内容,如需阅读全部内容,请付费购买文章所属专栏
《Java 业务开发常见错误 100 例》
新⼈⾸单¥59
立即购买
登录 后留言

全部留言(32)

  • 最新
  • 精选
  • 小阳
    置顶
    疑问: 代码3 的执行代码 ,forkJoinPool.execute(() -> IntStream.rangeClosed(1, taskCount).parallel().forEach(i -> increment(atomicInteger))); 我的理解是 通过自定义的forkJoinPool来将并行任务提交到公共的forkJoinPool去执行,因为 paraller().forEach()执行过程中并没提供像代码5那样设置用户的forkJoinPool,您说是在自定义的forkJoinPool执行increment(atomicInteger)的,这是为什么呢?

    作者回复: 看一下ForkJoinTask.fork()方法你就明白为什么能使用到自定义的ForkJoinPool了: public final ForkJoinTask<V> fork() { Thread t; if ((t = Thread.currentThread()) instanceof ForkJoinWorkerThread) ((ForkJoinWorkerThread)t).workQueue.push(this); else ForkJoinPool.common.externalPush(this); return this; }

    10
  • Darren
    置顶
    疑问:匿名内部类和Lambda到底有什么区别?为什么匿名内部类会生成$1这样的class文件而Lambda并没有??? 回答下问题: 1.项目中现在基本都是在使用Lambda表达式,主要是因为使用的vert.x和RxJava2,响应式变成基本都是Lambda; 2.并行效果消失,和去掉parallel()的效果是一样的,因为forEachOrdered将按照其源指定的顺序处理流的元素,而不管流是连续的还是并行的。 JavaDoc: forEach:The behavior of this operation is explicitly nondeterministic. For parallel stream pipelines, this operation does not guarantee to respect the encounter order of the stream, as doing so would sacrifice the benefit of parallelism. -------谷歌翻译------ 此操作的行为明确地是不确定的。 对于并行流管道,此操作不能保证尊重流的遇到顺序,因为这样做会牺牲并行性的好处。 对于任何给定的元素,可以在库选择的任何时间和线程中执行操作。 如果操作访问共享状态,则它负责提供所需的同步。 forEachOrdered :Performs an action for each element of this stream, in the encounter order of the stream if the stream has a defined encounter order. -------谷歌翻译----- 如果流具有定义的遇到顺序,则按流的遇到顺序对此流的每个元素执行操作。

    作者回复: lambda与普通的匿名内部类的实现方式不一样,可以参考一些资料,比如https://colobu.com/2014/11/06/secrets-of-java-8-lambda/ 这篇总结的很好: 编译时: - Lambda 表达式会生成一个方法, 方法实现了表达式的代码逻辑 - 生成invokedynamic指令, 调用bootstrap方法, 由java.lang.invoke.LambdaMetafactory.metafactory方法实现 运行时: - invokedynamic指令调用metafactory方法。 它会返回一个CallSite, 此CallSite返回目标类型的一个匿名实现类, 此类关联编译时产生的方法 - lambda表达式调用时会调用匿名实现类关联的方法。 forEachOrdered会让整个遍历过程失去并行化的效能,可以参考代码中的ForEachOrderedTest

    3
    19
  • 👽
    置顶
    检查下代码中是否有使用匿名类,以及通过遍历 List 进行数据过滤、转换和聚合的代码,看看能否使用 Lambda 表达式和 Stream 来重新实现呢? 已经使用lambda,stream快一年了,匿名类,基本就通过idea的自动处理,自己使用的基本上就:forEach,filter,map,这些。 对于并行流部分的并行消费处理 1 到 100 的例子,如果把 forEach 替换为 forEachOrdered,你觉得会发生什么呢? 个人猜测是会被有序化地多线程执行,四核CPU,1234 等一秒5678 这样。 但是,实际上,并发能力被直接移除。1等一秒,2等一秒,3......这样。不严谨的猜测,forEachOrdered 将本来的打印加上了类似于synchronized的效果。

    作者回复: forEachOrdered 会让parallelStream丧失部分的并行能力,主要是forEach的逻辑无法并行起来,比较: private void stream() { IntStream.rangeClosed(1, 10).filter(ForEachOrderedTest::filter).forEach(ForEachOrderedTest::consume); } private void parallelStream() { IntStream.rangeClosed(1, 10).parallel() .filter(ForEachOrderedTest::filter) .forEach(ForEachOrderedTest::consume); } private void parallelStreamForEachOrdered() { IntStream.rangeClosed(1, 10).parallel() .filter(ForEachOrderedTest::filter) .forEachOrdered(ForEachOrderedTest::consume); }

    2
  • 退而结网
    这个课程未免也太划算了,这个加餐囊括了好多其他的内容,物超所值,为老师点赞!打call

    作者回复: 后续加餐干货同样很多

    16
  • 刘大明
    想问下老师,既然Lambda 表达式这么简洁,方便,但是我们项目经理要我们在项目中不要使用他,说是不好调试.......这个是理由吗?

    作者回复: 其实IDEA已经增加了非常方便的Stream调试功能,可以参考https://www.jetbrains.com/help/idea/analyze-java-stream-operations.html

    6
    11
  • 杰哥长得帅
    想问一下大佬,把受检异常转换为运行时异常,有什么作用呢

    作者回复: 因为Function的签名不抛出受检异常IOException的,我们只能在flatMap中进行try...catch...了,这样就很不优雅臃肿,所以我们转换为运行时异常,这样就可以用一行代码来写完整个逻辑了

    3
  • 大头
    从传递对象,到传递匿名内部类,再到lambda表达式的演化,去掉了重复的代码,仅保留有意义的代码,越来越简洁明了了

    作者回复: 是,不仅仅是简化,函数式的概念其实从更本上可以改变设计的

    3
  • mgs2002
    forEachOrdered 保证元素按顺序执行,我测试了代码的例子,发现去掉parallel后执行时间跟forEach差不多,加上后执行时间快了一倍多,结论是forEachOrdered并没有使parallel并行化效果完全消失,是这样的吗,也尝试看了一下源码,有点蒙。。 以下是我的测试结果 246810421086246810StopWatch '': running time = 23068739988 ns --------------------------------------------- ns % Task name --------------------------------------------- 15051360863 065% stream 2010090132 009% parallelStream 6007288993 026% parallelStreamForEachOrdered

    作者回复: 因为filter还是并行的

    3
  • 👽
    java8的Lambda,给程序员提供了极大的便利性,和大幅度简化代码的可能性。单纯使用的话,学习成本并不高。常用的主流的操作也就那么几个。 但是要自行定义,并灵活变通使用,还是需要花些功夫去学习练习的。

    作者回复: 没错

    3
  • 陈天柱
    我实际开发的时候,最喜欢用的lambda表达式就是将一个集合对象转换成由该对象的指定字段值组成的集合,以前只会用,看了老师的文章以后才意识到学东西还是需要系统! 关于第二个思考题,尝试去阅读了一下源码,发现完全懵逼了,所以直接用idea跑了一下代码发现并行流forEachOrderd的效果直接是串行化了,虽然使用了并行流,但需要让任务有序化,让我想起了RocketMq里的顺序消息。

    作者回复: 可以比较一下源码中的ForEachOrderedTest

    2
收起评论
显示
设置
留言
32
收藏
沉浸
阅读
分享
手机端
快捷键
回顶部