java8函数式编程(四)

Java8 函数式编程 Stream 使用一种类似用 SQL 语句从数据库查询数据的直观方式来对 Java 集合运算和表达的高阶抽象。Stream API 可以极大提高 Java 程序员的生产力,让程序员写出高效率、干净、简洁的代码。这种风格将要处理的元素集合看作一种流, 流在管道中传输, 并且可以在管道的节点上进行处理, 比如筛选, 变换,聚合等。 阅读详情

相关链接:

java8函数式编程(一)
java8函数式编程(二)
java8函数式编程(三)

  其中(一)是在没有开始了解java8新特性之前实际遇到的一个问题,使用for循环实现的代码很繁琐,于是尝试使用新的编码风格,最后很不完美的实现了需求。在进一步学习后,在(二)中完美实现,并对List常用的操作做了一个总结。最后在(三)中对并行化流与并行化数组的操作简单归纳。
  本节主要是对java8流处理一个总结以及一些细节的补充。另外,学习资料主要参考《Java8实战》与《Java8函数式编程》两本书籍。


Stream API

优点:

1 声明性 – 简洁、易读
2 可复合 – 灵活组合
3 可并行 – 高性能

常用操作:
1 筛选
filter  过滤
distinct  去重
limit   截断
skip   跳过
2 映射
map   转换
flatMap   扁平化转换
3 查找与匹配
anyMatch   至少有一个满足
allMatch   所有都满足
noneMatch   没有一个满足
findAny   返回任意一个
findFrist   返回第一个
4 归约
reduce   计算
count   元素个数
5 数值流
mapToInt     IntStream
mapToDouble  DoubleStream
max    最大
min    最小
average   平均
boxed   数值流装箱
range   范围内(不包括end)
reageClosed  范围内(包括end)
6 构建流
of
iterate
generate
7 收集器
collect

数值操作

从1到20间的奇数

IntStream.rangeClosed(1, 20)
                .filter(n -> n%2 != 0)
                .forEach(System.out::println);

100以内奇数的和

int sum = IntStream.range(1, 100)
                .filter(n -> n % 2 != 0)
                .sum();

斐波那契数列(前20位)

Stream.iterate(new int[]{0,1}, n -> new int[]{n[1], n[0] + n[1]})
                .limit(20)
                .map(n -> n[0])
                .forEach(System.out::println);

collect收集器

准备数据依然使用List<Frog>,frog的属性有name名称,age年龄,color颜色,size体积。

        List<Frog> list = new ArrayList<>();
        list.add(new Frog("one", 2 , "red", 5.1));
        list.add(new Frog("two", 3 , "red", 5.0));
        list.add(new Frog("three", 2 , "blue", 5.5));
        list.add(new Frog("four", 1 , "blue", 5.3));
        list.add(new Frog("five", 5 , "yellow", 5.1));
        list.add(new Frog("six", 3 , "yellow", 5.2));

collect方法参数Collector。Collector接口中方法实现对流执行的操作,Collectors实现类提供很多静态方法,下面是对这些静态方法的说明。
为了代码简洁,导入Collectors类中所有方法:

import static java.util.stream.Collectors.*;
summaryStatistics

该方法可以一次性获取到数量、总和、最大值、最小值和平均数

DoubleSummaryStatistics summaryStatistics = frogs.stream()
                .collect(summarizingDouble(Frog::getSize));
System.out.println(summaryStatistics);

打印结果

DoubleSummaryStatistics{count=6, sum=31.200000, min=5.000000, average=5.200000, max=5.500000}

也可以直接通过summaryStatistics 的getter方法获取某一项。

joining

字符串的连接,方法重载

String names = frogs.stream()
                .map(Frog::getName)
                .collect(joining(" ", "[", "]"));

打印结果

[one two three four five six]
groupingBy

1、分组与多级分组

Map<String, List<Frog>> map = frogs.stream()
                .collect(groupingBy(Frog::getColor));

Map<String, Map<Volume, List<Frog>>> map1 = frogs.stream()
                .collect(groupingBy(Frog::getColor,
                        groupingBy(frog -> {
                            if (frog.getSize() < 5.2) {
                                return Volume.SMALL;
                            } else {
                                return Volume.BIG;
                            }
                        })));
                    
public enum Volume {
        BIG,
        SMALL
}

打印结果

{
 red=[Frog{name='one', age=2, color='red', size=5.1}, Frog{name='two', age=3, color='red', size=5.0}],
 blue=[Frog{name='three', age=2, color='blue', size=5.5}, Frog{name='four', age=1, color='blue', size=5.3}],
 yellow=[Frog{name='five', age=5, color='yellow', size=5.1}, Frog{name='six', age=3, color='yellow', size=5.2}]
 }

{
 red={
 	SMALL=[Frog{name='one', age=2, color='red', size=5.1}, Frog{name='two', age=3, color='red', size=5.0}]
 	},
 blue={
 	BIG=[Frog{name='three', age=2, color='blue', size=5.5}, Frog{name='four', age=1, color='blue', size=5.3}]
 	}, 
 yellow={
 	BIG=[Frog{name='six', age=3, color='yellow', size=5.2}], 
 	SMALL=[Frog{name='five', age=5, color='yellow', size=5.1}]
 	}
}

groupingBy第二个参数可以使用mapping方法。例:

Map<String, HashSet<Volume>> map4 = frogs.stream()
                .collect(groupingBy(Frog::getColor,
                        mapping(frog -> {
                            if (frog.getSize() < 5.2) {
                                return Volume.SMALL;
                            } else {
                                return Volume.BIG;
                            }
                        }, toCollection(HashSet::new))));

2、分组后的数据操作,比如按颜色分组,求每组中size最大的元素

Map<String, Frog> map2 = frogs.stream()
                .collect(groupingBy(Frog::getColor,
                        collectingAndThen(minBy(Comparator.comparingDouble(Frog::getSize)), Optional::get)));

等价的写法

Map<String, Frog> map3 = frogs.stream()
                .collect(toMap(Frog::getColor,
                        Function.identity(),
                        BinaryOperator.minBy(Comparator.comparingDouble(Frog::getSize))));

Function.identity():返回一个总是返回其输入参数的函数

partitioningBy

分区,分组的特殊情况,将数据分为true和false两组

Map<Boolean, Long> map = frogs.stream()
                .collect(partitioningBy(t -> t.getAge() > 1, counting()));

打印结果

{false=1, true=5}

实践

项目中遇到一个两级分组的问题,需要先按名称分组,然后再按标志(0/1)分组,对分组后的数量求和(库里String类型,实际需要按double类型求和)。代码如下:

Map<String, Map<String, Double>> map = list.stream()
                .collect(Collectors.groupingBy(Frog::getMc,
                        Collectors.groupingBy(Frog::getBz,
                                Collectors.summingDouble(t -> Double.parseDouble(t.getSl())))));

上面写法有一个计算精度问题,于是改成了一下方式:

Map<String, Map<String, BigDecimal>> map = list.stream()
                .collect(Collectors.groupingBy(Frog::getMc,
                        Collectors.groupingBy(Frog::getBz,
                                Collectors.reducing(new BigDecimal(0),
                                        t -> new BigDecimal(t.getSl()),
                                        (BigDecimal a, BigDecimal b) -> a.add(b)))));

用BigDecimal类型求和后精度是没有问题的,初除此之外还能对结果进行一些处理,比如保留两位小数(四舍五入)

BigDecimal number = new BigDecimal();
number.setScale(2,BigDecimal.ROUND_HALF_UP);

BigDecimal更多用法可以参考:
博主:星朝
链接:BigDecimal的用法详解(保留两位小数,四舍五入,数字格式化,科学计数法转数字,数字里的逗号处理)

Java 8的函数式编程:利用Java 8的lambda和Stream API,分享Java是如何采纳函数式编程思想的 Java 8新特性介绍 概述Java 8的新特性,如Lambda表达式、Stream API、函数式接口和默认方法 Lambda表达式 解释什么是Lambda表达式 介绍如何在Java中编写和使用Lambda表达式 举例(如使用lambda改写匿名内部类) 解析Lambda表达式的类型推断 展示使用Lambda表达式可带来的代码简化 函数式接口 介绍函数式接口的概念 介绍常用的函数式接口如Predicate, Function, Consumer, Supplier 阐述使用Lambda表达式实现函数式接口 阅读详情

相关推荐

IEEE LaTeX模板中algorithm排版避坑指南:如何优雅地嵌入算法描述?

本文详细解析了在IEEE LaTeX模板中优雅排版algorithm的实用技巧,包括基础配置、高级自定义及常见问题解决方案。通过嵌套环境与[H]参数的应用,帮助研究者克服IEEEtran模板对算法排版的限制,实现专业且美观的算法呈现。

weixin_28340315的博客 408

java中的函数式编程

3. 流式 API:流式 API 是一个用于处理集合数据的 API,其目的是以更清晰、更简洁的方式编写代码。1. Lambda 表达式:Lambda 表达式是一个可传递的匿名函数,可以直接传递给方法或存储在变量中,用于替代匿名内部类。2. 函数式接口:函数式接口是指只包含一个抽象方法的接口,通常使用 @FunctionalInterface 注解来标识。Java 8 引入了函数式编程特性,支持使用 Lambda 表达式、流式 API 等编写函数式风格的代码。3. 提高代码的可读性和可维护性。

qq_44113347的博客 626

HFSS求解器背后的数学原理:从麦克斯韦方程到S参数计算

本文深入解析了Ansys HFSS求解器的数学原理,从麦克斯韦方程出发,详细介绍了模式驱动求解(Driven Solution)和本征模求解(Eigenmode)等核心算法。通过有限元方法和模式匹配技术,HFSS将电磁场问题转化为矩阵方程求解,实现S参数计算和场分布分析,为工程师提供精确的电磁仿真工具。

weixin_28314575的博客 466

求和函数java_java函数求和要怎么写?java求和代码实现

小伙伴们知道在java中要怎么使用函数求和吗?数学函数一直是java逻辑上的重点,下面让我们通过一个实例来看看java是如何求和的吧。实例:packagecom;importjava.util.Scanner;publicclassAddadd{publicstaticvoidmain(String[]args){Scannerscan=newScanner(System....

weixin_39867327的博客 7084

国产Flash替代方案:手把手教你用XSCT烧写ZYNQ7045的BOOT.BIN(附完整命令解析)

本文详细介绍了国产Flash替代方案在ZYNQ7045上的应用,通过XSCT工具链实现BOOT.BIN的精准烧写。内容涵盖国产Flash兼容性检查、PetaLinux环境搭建、XSCT烧写全流程及故障排查,帮助开发者高效完成国产化替代,提升硬件开发效率。

weixin_33670786的博客 427

source tree clone error:fatal remote error: Repository not found

source tree clone error:fatal remote error: Repository not found

Linda的前端开发路 3077

使用Java实现算术求和(三种流程)

public class Sum100 { public static void main(String[] args) { int sum, n; System.out.println("\n**** for statement****"); sum=0; for(int i=1;i<=100;i++){ sum+=i; } System.out.println("sum.

Protinx的博客 3844

2026.2.23:AgentScope框架实战<一>:安装并使用agentscope

本文介绍了AgentScope框架的安装与使用实践。通过PyPI安装agentscope[full]后,演示了如何创建ReActAgent代理:1)配置DashScope聊天模型;2)注册自定义工具函数(查询位置和天气);3)初始化代理并处理用户请求。示例展示了代理如何响应复合查询(如同时获取北京位置和天气信息),输出结果显示代理成功执行了工具调用并返回结构化响应。该框架支持Python 3.13环境,提供内存管理、工具集成等功能,适用于构建智能代理系统。

拥抱具身智能,昇腾Ascend C 509

彻底吃透java8函数式编程

Lamda表达式 箭头左边是参数列表,右边是函数体。 方法引用 : class::method 静态方法引用: User::combine 参数方法引用: String::indexOf 实例方法引用: user::getUserName 构造器引用: User::new java函数式接口 有且仅有一个未实现的非静态方法的接口叫做“函数式接口” interface IProducer<T>{ T produce(); } // ()=>User.bu...

小米吃辣椒的博客 531

嵌入式面试题精选100道及参考答案(4万字长文)

指针是C语言中一种特殊的变量,它存储的是另一个变量的内存地址。指针的使用提供了一种间接访问和操作内存的方法。地址操作:通过使用运算符,可以获取变量的地址,并将这个地址赋值给指针变量。间接引用:使用运算符可以访问指针指向的变量的值。动态内存分配:指针用于动态地分配和释放内存。数组操作:指针可以用于遍历和操作数组。函数参数:指针作为函数参数可以改变原始数据。字符串操作:在C语言中,字符串通常以字符数组的形式存在,并通过字符指针进行操作。// 指向数组的第一个元素i < 5;++i) {在这个例子中,

大模型大数据攻城狮的专栏 1972

符合DO-178C和DO-331的机载软件研制体系

DO-178C的核心要求软件开发生命周期:DO-178C定义了软件开发的生命周期过程,包括需求获取、设计、实现、验证和确认等。它为机载软件开发提供了一套系统化的指导,确保在开发过程中考虑安全性和可靠性。安全等级(DAL):根据系统的重要性,DO-178C将软件划分为不同的开发保障等级(DAL A到E),DAL A的要求最为严格,适用于关键安全功能,而DAL E的要求较低,适用于非关键功能。DO-178C在非基于模型软件开发中的应用。

qq_41854911的博客 980

java函数式编程汇总

java流式编程经验总结以及示例

工匠精神coding,终生学习 1314

9.13华为OD机试真题 新系统 - 手机桌面整理 (Java/Py/C/C++/Js/Go)

华为OD机试真题 新系统【手机桌面整理】,提供C语言、Java、C++、Python、Go、JavaScript源码实现,并提供完整思路讲解,以及在线OJ模拟做题。华为OD机试真题 【 手机桌面整理】多语言题解。

qq_45776114的博客 640

java8函数式编程 视频_java8函数式编程调试<四>

继续看《java 8 函数式编程》,思考一些传达的设计思路吧。我们在调试时通常会设置断点,单步跟踪程序的每一步。使用流时,调试可能会变得更加复杂,因为迭代已交由类库控制,而且很多流操作是惰性求值的。然后先说一下java8由外部迭代到内部迭代,java程序员在使用集合类时,我们长做的事情就是在集合上进行迭代,然后处理返回的每一个元素。然后作者可能觉得每次迭代,需要写不少样本代码,并且将for循环改造...

weixin_32259697的博客 171

ssm框架搭建

这个是一个在idea上成功跑起来的ssm框架项目,保存在这里方便以后使用直接下载

Camera2Demo

在Camera2 的基础上进行封装,使得Camera2一堆初始化逻辑与Activity分离,降低耦合度,完成预览拍照并保存的操作

Java函数式编程(四)JDK8对库的增强

java 函数式编程 Lambda表达式 Stream 设计模式

yunyun1886358的专栏 626

Data-Structures-and-Algorithm-Analysis-in-Java.pdf

作者: Weiss, Mark A. 出版社: Addison Wesley Data Structures and Algorithm Analysis in Java is an “advanced algorithms” book that fits between traditional CS2 and Algorithms Analysis courses. In the old ACM Curriculum Guidelines, this course was known as CS7. This text is for readers who want to learn good programming and algorithm analysis skills simultaneously so that they can develop such programs with the maximum amo...

函数接口编程 java_Java8函数式编程之四: 常见的函数式接口及实例

上一篇博客中Java8函数式编程之三:函数式接口 - 简书留下的问题是关于Consumer接口的,本篇博客就来介绍一下Java8提供的重要的函数式接口。1.Consumer接口:我们首先看一下Consumer接口的Javadoc,比任何资料都正规的解释。'/*** Represents an operation that accepts a single input argument and r...

weixin_39576104的博客 181

win10 跳过U8环境检测的IE WebControls.rar

win10 安装u8的时候 提示IE WebControls 不通过,这个工具可以欺骗u8的检查。 跳过U8环境检测的IE WebControls。提示导入失败后,重新检测通过。

Java8函数式编程之四: 常见的函数式接口及实例

上一篇博客中留下的问题是关于Consumer接口的,本篇博客就来介绍一下Java8提供的重要的函数式接口。 1.Consumer接口:我们首先看一下Consumer接口的Javadoc,比任何资料都正规的解释。 '/*** Represents an operation that accepts a single input argument and returns no* result. Unl

zlz18225318697的博客 538

JAVA 8函数式编程(四):JAVA支持闭包吗?

如果闭包的定义如此简单,请参看百度百科对闭包的定义: 闭包包含自由(未绑定到特定对象)变量;这些变量不是在这个代码块内或者任何全局上下文中定义的,而是在定义代码块的环境中定义(局部变量)。 简单来说,就是可以绑定变量作用域,那么很显然,JAVA是完全支持闭包的,如下:static IntFunction<Integer> sumEx(int a) { // 定义局部变量 fin

甘焕的博客 2465

Java8函数式编程-包教包会系列(四)

作者:曹伟,叩丁狼教育高级讲师。原创文章,转载请注明出处。内置函数式接口常用的内置函数式接口JDK提供了大量常用的函数式接口以丰富Lambda的典型使用场景,它们主要在java.util.function包中被提供。上面用到过的Consumer接口就是其中之一,接下来给大家介绍下其他的常用函数式接口代码演示 public class FunctionDemo { // 函数式接...

wolfcode_cn的博客 455

学习 Java8 函数式编程 (四)

扯淡 按照之前的习惯,本文的开头依旧是扯淡。其实,做软件开发确实非常难,我们需要经常学习新的技术,我们还要有几门非常精通的技术。因为这些,我们需要花费大量的时间在工作和学习上。正好,坚持写技术博客能够提高我们学习的效率,同时有利于技术的沉淀和积累。把技术博客写好是件非常困难的事,这需要我们长...

chengju7525的博客 150

java书第十四章上机四_《java 8 实战》读书笔记 -第十四章 函数式编程的技巧

一、无处不在的函数一等函数:能够像普通变量一样使用的函数称为一等函数(first-class function)通过::操作符,你可以创建一个方法引用,像使用函数值一样使用方法,也能使用Lambda表达式(比如,(int x) -> x + 1)直接表示方法的值。Function strToInt = Integer::parseInt;1.高阶函数能满足下面任一要求就可以被称为高阶函数(h...

weixin_32708653的博客 224

Java8函数式编程(1)--Principle

核心概念 Java8是怎么支持函数编程的呢?主要有三个核心概念: 函数接口(Function) 流(Stream) 聚合器(Collector) 函数接口 关于函数接口,需要记住的就是两件事: 函数接口是行为的抽象; 函数接口是数据转换器。 最直接的支持就是 java.util.Function 包。定义了四个最基础的函数接口: Supplier<T>:...

demon7552003的小本本 371

Java8函数式编程

最近使用lambda表达式,感觉使用起来非常舒服,箭头函数极大增强了代码的表达能力。于是决心花点时间深入地去研究一下java8的函数式。 (想自学习编程的小伙伴请搜索圈T社区,更多行业相关资讯更有行业相关免费视频教程。完全免费哦!) 一、lambda表达式 先po一个最经典的例子——线程 public static void main(String[] args) { // Java7 n...

wanghao112956的博客 2万+

Java函数式编程详解

Java从1.8以后引入了函数式编程,这是很大的一个改进。函数式编程的优点在提高编码的效率,增强代码的可读性。本文历时两个多月一点点写出来,即作为心得,亦作为交流。 1.Java函数式编程的语法: 使用Consumer作为示例,它是一个函数式接口,包含一个抽象方法accept,这个方法只有输入而无输出也就是说这个方法无返回值。 现在我们要定义一个Consumer接口的实例化对象,传统的方式是...

陈大伟的博客 3万+

Java函数式编程入门

函数式编程在Java中不仅能提高代码的简洁性和可读性,还能在处理数据流、并行计算等场景中发挥重要作用。通过掌握Lambda表达式、Stream API、Optional以及其他相关技术,并结合实际业务场景的应用,你将能够更高效地开发出安全、稳定和可维护的系统。建议在日常项目中逐步引入函数式编程思想,从简单的集合操作开始,逐步探索更多高级特性,并结合代码评审和测试不断完善实践经验。/*** 函数式编程*//*** Function<T, R>:接受T类型的参数,返回R类型的结果。

zjh285077371的专栏 1779
上一篇: java8时间API
下一篇: 2018总结
litte_frog
博客等级 码龄9年 39粉丝 50原创
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值