Java从入门到精通笔记篇(十三)

与流处理

ambda表达式

定义

lambda表达式不能被独立执行,因此必须实现函数式接口,并且会返回一个函数式接口的对象。

可将其语法用下列的方式理解

误区警示

"->"符号是由英文状态下的"-"和">"组成的,符号之间没有空格。

lambda表达式中可以用"(a1,a2,a3)"的方法表示有参抽象方法,圆括号里的标识符对应抽象方法的参数。如果抽象方法中只有一个参数,lambda表达式则可以省略圆括号。

lambda表达式中的参数不需要与抽象方法的参数名称相同,但顺序必须相同。

lambda表达式调用外部变量

无法更改局部变量

局部变量在lambda表达式中默认被定义为final,lambda表达式只能调用局部变量,无法更改局部变量。

错误示范

可以更改类成员变量

lambda表达式可以调用并修改类成员变量的值。

lambda表达式只是描述了抽象方法是如何实现的,在抽象方法没有被调用前,lambda表达式中的代码并没有被执行,因此在运行抽象方法之前类成员变量的值不会发生变化。

只要抽象方法被调用,就会执行lambda表达式中的代码,类成员变量的值也就会被修改。

lambda表达式与异常处理

lambda表达式没有定义异常,但会默认抛出抽象方法原有的异常,当此方法被调用时则需要进行异常处理。

实例

创建自定义异常UnderAgeException,当发现用户是未成年人时进入此异常处理。创建函数式接口,在抽象方法中抛出UnderAgeException异常,使用lambda表达式实现此接口,并让接口对象执行抽象方法。

方法的引用

ambda表达式中方法也可以作为一个对象被调用。

引用静态方法

类名::静态方法名

::由两个英文冒号组成的操作符,冒号之间没有空格。

注意:语法中方法名是没有圆括号的。

引用成员方法

对象名::成员方法名

引用带泛型的方法

"::"操作符支持引用带泛型的方法。也支持引用带泛型的类。

与其他使用泛型的场景一样,要保证代码前后泛型一致

引用构造方法

lambda表达式有3种引用构造方法的语法,分别是引用无参构造方法、引用有参构造方法和引用数组构造方法

引用无参构造方法

类名::new

构造方法与类名相同,如果在操作符左右都写上类名,会让操作符误以为是在引用与类名相同的静态方法,这样会导致程序出现bug,所以在操作符右侧写上new关键字,表示引用构造方法。

注意:new关键字之后没有圆括号,也没有参数的定义。如果类中既有无参构造方法,又有有参构造方法,使用引用构造方法语法后,究竟哪一个构造方法被引用了呢?引用哪个构造方法是由函数式接口决定的,"::"操作符会返回与抽象方法的参数结构相同的构造方法。

例如,返回的是调用无参构造方法

引用有参构造方法与引用无参构造方法的语法一样。区别就是函数式接口的抽象方法是有参数的。

引用数组构造方法

类名[]::new

Function接口

使用lambda表达式都需要先创建或调用已有的函数式接口,但java.util.function包已经提供了很多预定义函数式接口。最常用的接口是Function<T,R>

T:被操作的类型,可以理解为方法参数类型。

R:操作结果类型,可以理解为方法的返回类型。

流处理

流处理有点类似数据库的SQL语句,可以执行非常复杂的过滤、映射、查找和收集功能,并且代码量很少。

Stream接口

流处理的接口都被定义在java.uil.stream包中。BaseStream接口是最基础的接口,但最常用的是BaseStream接口的一个子接口---Stream接口。

Stream接口是泛型接口,因此流中操作的元素可以是任何类的对象。

表中最后一列"类型"中有两种值:中间操作和终端操作。中间操作类型的方法会生成一个新的流对象,被操作的流对象仍然可以执行其他操作;终端操作会消费流,操作结束之后,被操作的流对象就不能再次执行其他操作了。这是二者的最大区别。

Collection接口新增两个可以获取流对象的方法。

可以获取集合的顺序流

Stream<E> stream();

获取集合的并行流

Stream<E> parallelstream();

Optional类

Optional类保存的值不会是null

Optional类由于是用final修饰的,因此不能有子类。

Optional类由于是带有泛型的类,因此可以保存任何对象的值。

Optional类中有一个叫作value的成员属性,这个属性就是用来保存具体值的。value是用泛型T修饰的,并且还用了final修饰,这表示一个Optional对象只能保存一个值。

数据过滤

filter()方法是Stream接口提供的过滤方法。

将lambda表达式作为参数,然后按照lambda表达式的逻辑过滤流中的元素。

过滤出想要的流元素后,还需Stream提供的collect()方法重新进行封装。

distinct()方法是Stream接口提供的过滤方法。该方法可以去除流中的重复元素,效果与SQL语句中的DISTINCT关键字一样。

limit()方法是Stream接口提供的方法,该方法可以获取流中前N个元素。

skip()方法是Stream接口提供的方法,该方法可以忽略流中的前n个元素。

数据映射

过滤是在流中找到符合条件的元素,映射是在流中获得具体的数据。

Stream接口提供了map()方法用来实现数据映射,map()方法会按照参数中的函数逻辑获取新的流对象,新的流对象中元素类型可能与旧流对象元素类型不相同。

数据查找

本节所讲的数据查找并不是在流中获取数据(这属于数据过滤),而是判断流中是否有符合条件的数据,查找的结果是一个boolean值或一个Optional类的对象。

allMatch()方法是Stream接口提供的方法,该方法会判断流中的元素是否全部符合某一条件,返回结果是boolean值。如果所有元素都符合条件,则返回true,否则返回false。

anyMatch()方法是Stream接口提供的方法,该方法会判断流中的元素是否有符合某一条件,只要有一个元素符合条件就返回true,如果没有元素符合条件,则会返回false。

noneMatch()方法是Stream接口提供的方法,该方法会判断流中的所有元素是否都不符合某一条件。这个方法的逻辑和allMatch()方法正好相反。

findFirst()方法是Stream接口提供的方法,这个方法会返回符合条件的第一个元素。注意这个方法的返回值不是boolean值,而是一个Optional对象。

数据收集

数据统计

数据分组

一级分组,就是将所有数据按照一个条件进行归类,而不再细分 。

Collectors类提供的groupingBy()方法就是用来进行分组的方法,方法参数是一个Function接口对象,收集器会按照指定的函数规则对数据分组。

分组规则是一个函数,这个函数是由Collectors收集器类调用的,而不是Stream流对象。

运行结果

多级分组

按照多个条件进行分组的

学校有100名学生,这些学生分布在3个年级中,这是一级分组,但每个年级还有若干个班级,学生被分到不同年级之后又被分到不同的班里,这就是二级分组。如果学生再被按男女分组,就变成了三级分组。元素按照两个以上的条件进行分组,就是多级分组。

运行结果

注意:

groupingBy()方法的参数不同

Map对象的嵌套,即从左数,第一个Map对象做了一级分组,第二个Map对象做了二级分组。

相关推荐
0白露1 小时前
Apifox Helper 与 Swagger3 区别
开发语言
Tanecious.2 小时前
机器视觉--python基础语法
开发语言·python
叠叠乐2 小时前
rust Send Sync 以及对象安全和对象不安全
开发语言·安全·rust
战族狼魂2 小时前
CSGO 皮肤交易平台后端 (Spring Boot) 代码结构与示例
java·spring boot·后端
Tttian6223 小时前
Python办公自动化(3)对Excel的操作
开发语言·python·excel
xyliiiiiL3 小时前
ZGC初步了解
java·jvm·算法
杉之4 小时前
常见前端GET请求以及对应的Spring后端接收接口写法
java·前端·后端·spring·vue
hycccccch4 小时前
Canal+RabbitMQ实现MySQL数据增量同步
java·数据库·后端·rabbitmq
独好紫罗兰4 小时前
洛谷题单2-P5713 【深基3.例5】洛谷团队系统-python-流程图重构
开发语言·python·算法
zhuyixiangyyds5 小时前
day21和day22学习Pandas库
笔记·学习·pandas