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

本文介绍了Java8中数值流的使用,包括流与数值流的转换、数值流的方法、范围处理以及Optional类的作用。还探讨了如何通过流构建高效操作,以及collect方法的多种用途,如汇总和平均计算。此外,提及了Java开发者的学习资源,特别是对于面试准备的帮助。
摘要由CSDN通过智能技术生成

一、数值流


前面介绍的如int sum = list.stream().map(Person::getAge).reduce(0, Integer::sum); 计算元素总和的方法其中暗含了装箱成本,map(Person::getAge) 方法过后流变成了 Stream 类型,而每个 Integer 都要拆箱成一个原始类型再进行 sum 方法求和,这样大大影响了效率。

针对这个问题 Java 8 有良心地引入了数值流 IntStream, DoubleStream, LongStream,这种流中的元素都是原始数据类型,分别是 int,double,long。

1、流与数值流的转换

流转换为数值流

  • mapToInt(T -> int) : return IntStream

  • mapToDouble(T -> double) : return DoubleStream

  • mapToLong(T -> long) : return LongStream

IntStream intStream = list.stream().mapToInt(Person::getAge);

当然如果是下面这样便会出错

LongStream longStream = list.stream().mapToInt(Person::getAge);

因为 getAge 方法返回的是 int 类型(返回的如果是 Integer,一样可以转换为 IntStream)

数值流转换为流

很简单,就一个 boxed

Stream stream = intStream.boxed();

2、数值流方法

下面这些方法作用不用多说,看名字就知道:

  • sum()

  • max()

  • min()

  • average() 等…

3、数值范围

IntStream 与 LongStream 拥有 range 和 rangeClosed 方法用于数值范围处理

  • IntStream : rangeClosed(int, int) / range(int, int)

  • LongStream : rangeClosed(long, long) / range(long, long)

这两个方法的区别在于一个是闭区间,一个是半开半闭区间:

  • rangeClosed(1, 100) :[1, 100]

  • range(1, 100) :[1, 100)

我们可以利用 IntStream.rangeClosed(1, 100) 生成 1 到 100 的数值流

// 求 1 到 10 的数值总和:

IntStream intStream = IntStream.rangeClosed(1, 10);

int sum = intStream.sum();

二、Optional 类


NullPointerException 可以说是每一个 Java 程序员都非常讨厌看到的一个词,针对这个问题, Java 8 引入了一个新的容器类 Optional,可以代表一个值存在或不存在,这样就不用返回容易出问题的 null。之前文章的代码中就经常出现这个类,也是针对这个问题进行的改进。

Optional 类比较常用的几个方法有:

  • isPresent() :值存在时返回 true,反之 flase

  • get() :返回当前值,若值不存在会抛出异常

  • orElse(T) :值存在时返回该值,否则返回 T 的值

Optional 类还有三个特化版本 OptionalInt,OptionalLong,OptionalDouble,刚刚讲到的数值流中的 max 方法返回的类型便是这个。

Optional 类其中其实还有很多学问,讲解它说不定也要开一篇文章,这里先讲那么多,先知道基本怎么用就可以。

三、构建流


之前我们得到一个流是通过一个原始数据源转换而来,其实我们还可以直接构建得到流。

1、值创建流

  • Stream.of(T…) : Stream.of(“aa”, “bb”) 生成流

// 生成一个字符串流

Stream stream = Stream.of(“aaa”, “bbb”, “ccc”);

  • Stream.empty() : 生成空流

2、数组创建流

根据参数的数组类型创建对应的流:

  • Arrays.stream(T[ ])

  • Arrays.stream(int[ ])

  • 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

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

深知大多数Java工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

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

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Java开发知识点,真正体系化!

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

如果你觉得这些内容对你有帮助,可以扫码获取!!(备注Java获取)

img

本次面试答案,以及收集到的大厂必问面试题分享:

字节跳动超高难度三面java程序员面经,大厂的面试都这么变态吗?

《互联网大厂面试真题解析、进阶开发核心学习笔记、全套讲解视频、实战项目源码讲义》点击传送门即可获取!

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Java开发知识点,真正体系化!

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

如果你觉得这些内容对你有帮助,可以扫码获取!!(备注Java获取)

img

本次面试答案,以及收集到的大厂必问面试题分享:

[外链图片转存中…(img-z64xezBm-1712627805553)]

《互联网大厂面试真题解析、进阶开发核心学习笔记、全套讲解视频、实战项目源码讲义》点击传送门即可获取!

  • 4
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值