Java新特性:Java8 Stream 简单快速的处理集合(三)

  • Arrays.stream(double[ ])

  • Arrays.stream(long[ ])

值得注意的是,还可以规定只取数组的某部分,用到的是Arrays.stream(T[], int, int)

// 只取索引第 1 到第 2 位的:

int[] a = {1, 2, 3, 4};

Arrays.stream(a, 1, 3).forEach(System.out :: println);

// 打印 2 ,3

3、文件生成流

Stream stream = Files.lines(Paths.get(“data.txt”));

每个元素是给定文件的其中一行

4、函数生成流

两个方法:

  • iterate : 依次对每个新生成的值应用函数

  • generate :接受一个函数,生成一个新的值

Stream.iterate(0, n -> n + 2)

// 生成流,首元素为 0,之后依次加 2

Stream.generate(Math :: random)

// 生成流,为 0 到 1 的随机双精度数

Stream.generate(() -> 1)

// 生成流,元素全为 1

四、collect 收集数据


collect 方法作为终端操作,接受的是一个 Collector 接口参数,能对数据进行一些收集归总操作

1、收集

最常用的方法,把流中所有元素收集到一个 List, Set 或 Collection 中

  • toList

  • toSet

  • toCollection

  • toMap

List newlist = list.stream.collect(toList());

// 如果 Map 的 Key 重复了,可是会报错的哦

Map<Integer, Person> map = list.stream().collect(toMap(Person::getAge, p -> p));

2、汇总

(1)counting

用于计算总和:

long l = list.stream().collect(counting());

没错,你应该想到了,下面这样也可以:

long l = list.stream().count();

推荐第二种

(2)summingInt ,summingLong ,summingDouble

summing,没错,也是计算总和,不过这里需要一个函数参数

计算 Person 年龄总和:

int sum = list.stream().collect(summingInt(Person::getAge));

当然,这个可以也简化为:

int sum = list.stream().mapToInt(Person::getAge).sum();

除了上面两种,其实还可以:

int sum = list.stream().map(Person::getAge).reduce(Interger::sum).get();

推荐第二种

由此可见,函数式编程通常提供了多种方式来完成同一种操作

(3)averagingInt,averagingLong,averagingDouble

看名字就知道,求平均数

Double average = list.stream().collect(averagingInt(Person::getAge));

当然也可以这样写

OptionalDouble average = list.stream().mapToInt(Person::getAge).average();

不过要注意的是,这两种返回的值是不同类型的

(4)summarizingInt,summarizingLong,summarizingDouble

这三个方法比较特殊,比如 summarizingInt 会返回 IntSummaryStatistics 类型

IntSummaryStatistics l = list.stream().collect(summarizingInt(Person::getAge));

IntSummaryStatistics 包含了计算出来的平均值,总数,总和,最值,可以通过下面这些方法获得相应的数据

在这里插入图片描述

3、取最值

maxBy,minBy 两个方法,需要一个 Comparator 接口作为参数

Optional optional = list.stream().collect(maxBy(comparing(Person::getAge)));

我们也可以直接使用 max 方法获得同样的结果

Optional optional = list.stream().max(comparing(Person::getAge));

4、joining 连接字符串

也是一个比较常用的方法,对流里面的字符串元素进行连接,其底层实现用的是专门用于字符串连接的 StringBuilder

String s = list.stream().map(Person::getName).collect(joining());

// 结果:jackmiketom

String s = list.stream().map(Person::getName).collect(joining(“,”));

// 结果:jack,mike,tom

joining 还有一个比较特别的重要方法:

String s = list.stream().map(Person::getName).collect(joining(" and ", "Today “, " play games.”));

// 结果:Today jack and mike and tom play games.

即 Today 放开头,play games. 放结尾,and 在中间连接各个字符串

5、groupingBy 分组

groupingBy 用于将数据分组,最终返回一个 Map 类型

Map<Integer, List> map = list.stream().collect(groupingBy(Person::getAge));

例子中我们按照年龄 age 分组,每一个 Person 对象中年龄相同的归为一组

另外可以看出,Person::getAge 决定 Map 的键(Integer 类型),list 类型决定 Map 的值(List 类型)

多级分组

groupingBy 可以接受一个第二参数实现多级分组:

Map<Integer, Map<T, List>> map = list.stream().collect(groupingBy(Person::getAge, groupingBy(…)));

其中返回的 Map 键为 Integer 类型,值为 Map<T, List> 类型,即参数中 groupBy(…) 返回的类型

按组收集数据

Map<Integer, Integer> map = list.stream().collect(groupingBy(Person::getAge, summingInt(Person::getAge)));

该例子中,我们通过年龄进行分组,然后 summingInt(Person::getAge)) 分别计算每一组的年龄总和(Integer),最终返回一个 Map<Integer, Integer>

根据这个方法,我们可以知道,前面我们写的:

groupingBy(Person::getAge)

其实等同于:

groupingBy(Person::getAge, toList())

6、partitioningBy 分区

分区与分组的区别在于,分区是按照 true 和 false 来分的,因此partitioningBy 接受的参数的 lambda 也是 T -> boolean

// 根据年龄是否小于等于20来分区

Map<Boolean, List> map = list.stream()

.collect(partitioningBy(p -> p.getAge() <= 20));

// 打印输出

{

false=[Person{name=‘mike’, age=25}, Person{name=‘tom’, age=30}],

true=[Person{name=‘jack’, age=20}]

}

同样地 partitioningBy 也可以添加一个收集器作为第二参数,进行类似 groupBy 的多重分区等等操作。

五、并行


我们通过 list.stream() 将 List 类型转换为流类型,我们还可以通过 list.parallelStream() 转换为并行流。因此你通常可以使用 parallelStream 来代替 stream 方法

并行流就是把内容分成多个数据块,使用不同的线程分别处理每个数据块的流。这也是流的一大特点,要知道,在 Java 7 之前,并行处理数据集合是非常麻烦的,你得自己去将数据分割开,自己去分配线程,必要时还要确保同步避免竞争。

Stream 让程序员能够比较轻易地实现对数据集合的并行处理,但要注意的是,不是所有情况的适合,有些时候并行甚至比顺序进行效率更低,而有时候因为线程安全问题,还可能导致数据的处理错误,这些我会在下一篇文章中讲解。

比方说下面这个例子

int i = Stream.iterate(1, a -> a + 1).limit(100).parallel().reduce(0, Integer::sum);

流的可分解性

这就说到流的可分解性问题了,使用并行的时候,我们要注意流背后的数据结构是否易于分解。比如众所周知的 ArrayList 和 LinkedList,明显前者在分解方面占优。

最后

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数Java工程师,想要提升技能,往往是自己摸索成长,自己不成体系的自学效果低效漫长且无助。

因此收集整理了一份《2024年Java开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Java开发知识点,不论你是刚入门Android开发的新手,还是希望在技术上不断提升的资深开发者,这些资料都将为你打开新的学习之门!

如果你觉得这些内容对你有帮助,需要这份全套学习资料的朋友可以戳我获取!!

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!
年进入阿里一直到现在。**

深知大多数Java工程师,想要提升技能,往往是自己摸索成长,自己不成体系的自学效果低效漫长且无助。

因此收集整理了一份《2024年Java开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。

[外链图片转存中…(img-ddDlsibk-1715435162416)]

[外链图片转存中…(img-7EISgs4k-1715435162417)]

[外链图片转存中…(img-wGyFFylf-1715435162417)]

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Java开发知识点,不论你是刚入门Android开发的新手,还是希望在技术上不断提升的资深开发者,这些资料都将为你打开新的学习之门!

如果你觉得这些内容对你有帮助,需要这份全套学习资料的朋友可以戳我获取!!

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!

  • 19
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值