Java新特性:Stream流式编程

这篇具有很好参考价值的文章主要介绍了Java新特性:Stream流式编程。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

Java新特性:Stream流式编程

Stream 流是 Java8 提供的新功能,是对集合对象功能的增强,能对集合对象进行各种非常便利、高效的聚合操作,或大批量数据操作。Stream 流以一种声明性方式处理数据集合,它提供串行和并行两种模式进行汇聚操作,并发模式能够充分利用多核处理器的优势,使用fork/join并行方式来拆分任务和加速处理过程。

Stream 流是从支持数据处理操作的源生成的元素序列,源可以是数组、文件、集合、函数。流不是集合元素,它不是数据结构并不保存数据,它的主要目的在于计算



1、Stream流概述
1.1、Stream流简介

Stream 流是 Java8 提供的新功能,是对集合对象功能的增强,能对集合对象进行各种非常便利、高效的聚合操作,或大批量数据操作。Stream 流以一种声明性方式处理数据集合,它提供串行和并行两种模式进行汇聚操作,并发模式能够充分利用多核处理器的优势,使用fork/join并行方式来拆分任务和加速处理过程。

Stream 流是从支持数据处理操作的源生成的元素序列,源可以是数组、文件、集合、函数。流不是集合元素,它不是数据结构并不保存数据,它的主要目的在于计算

Stream 流是对集合(Collection)对象功能的增强,与 Lambda 表达式结合,可以提高编程效率、简洁性和程序可读性。使用 Stream API 无需编写一行多线程的代码,就可以很方便地写出高性能的并发程序。

1.2、Stream流的构成

当我们使用一个流的时候,通常包括三个基本步骤:

获取一个数据源(source)→ 数据转换 → 执行操作获取想要的结果,每次转换原有 Stream 对象不改变,返回一个新的 Stream 对象(可以有多次转换),这就允许对其操作可以像链条一样排列,变成一个管道,如下图所示:

Java新特性:Stream流式编程,Java基础,java,python,数据库

我们将 Java 中的流式编程分为三个操作步骤:

  1. 创建数据源:创建 Stream 流,从集合、数组中获取一个流
  2. 中间操作:中间操作链,对数据进行处理
  3. 终端操作:用来执行中间操作链,返回结果

下面我们结合这三个步骤来分别讨论,Stream 流中的方法。

1.3、Stream流特点
  1. 代码简洁:函数式编程写出的代码简洁且意图明确,使用 Stream 接口让我们从此告别 for 循环;
  2. 多核友好:Java 函数式编程使得编写并行程序如此简单,就是调用一下方法
1.4、Stream流特点
  1. Stream 自己不会存储元素;
  2. Stream 的操作不会改变源对象,相反,他们会返回一个持有结果的新 Stream;
  3. Stream 操作是延迟执行的,它会等到需要结果的时候才执行,也就是执行终端操作的时候

2、Java中的流式编程:创建Stream数据流

生成流的方式主要有五种:

2.1、Stream创建

使用静态方法 Stream.of(),通过显式值创建一个流

Stream<Integer> stream = Stream.of(0, 1, 2, 3, 4, 5);
2.2、Collection创建

Collection 集合创建(应用中最常用的一种)

List<Integer> integerList = new ArrayList<>();
integerList.add(0);
integerList.add(1);
integerList.add(2);
integerList.add(3);
integerList.add(4);
integerList.add(5);
Stream<Integer> listStream = integerList.stream();
2.3、Arrays创建

Arrays 数组创建,将数组作为数据源,读取数组中的数据到一个流中

int[] intArr = {0, 1, 2, 3, 4, 5};
IntStream arrayStream = Arrays.stream(intArr);
2.4:文件创建

通过 Files.line() 方法得到一个流,并且得到的每个流是给定文件中的一行

try {
     Stream<String> fileStream = Files.lines(Paths.get("data.txt"), Charset.defaultCharset());
} catch (IOException e) {
     e.printStackTrace();
}
2.5:函数创建

函数创建,创建无限流

Stream.iterator() 方法接受两个参数,第一个为初始化值,第二个为进行的函数操作,因为 iterator 生成的流为无限流,通过 limit 方法对流进行了截断

Stream<Integer> iterateStream = Stream.iterate(0, n -> n + 2).limit(5);

Stream.generate() 方法接受一个参数,方法参数类型为 Supplier ,由它为流提供值。generate 生成的流也是无限流,因此通过 limit 对流进行了截断

Stream<Double> generateStream = Stream.generate(Math::random).limit(5);

3、Java中的流式编程:中间操作

通常对于 Stream 的中间操作,可以视为是源的查询,并且是懒惰式的设计,对于源数据进行的计算只有在需要时才会被执行,与数据库中视图的原理相似;

Stream 流的强大之处便是在于提供了丰富的中间操作,相比集合或数组这类容器,极大的简化源数据的计算复杂度。一个流可以跟随零个或多个中间操作。其目的主要是打开流,做出某种程度的数据映射/过滤,然后返回一个新的流,交给下一个操作使用这类操作都是惰性化的,仅仅调用到这类方法,并没有真正开始流的遍历,真正的遍历需等到终端操作时,常见的中间操作有下面即将介绍的 filter、map 等。

3.1、filter 过滤

filter 条件过滤,以将流中满足指定条件的数据保留,去掉不满足指定条件的数据

// filter:输出ID大于6的user对象
List<User> filetrUserList = userList.stream().filter(user -> user.getId() > 6).collect(Collectors.toList());
filetrUserList.forEach(System.out::println);
3.2、map 映射

map 元素映射,提供一个映射规则,将流中的每一个元素替换成指定的元素

// map
List<String> mapUserList = userList.stream().map(user -> user.getName() + "用户").collect(Collectors.toList());
mapUserList.forEach(System.out::println);
3.3、distinct 去重

distinct 去重,去除流中的重复的数据,这个方法是没有参数的,去重的规则与 hashSet 相同

// 去重
dataSource.distinct().forEach(System.out::println); 
3.4、sorted 排序

sorted 排序,将流中的数据,按照其对应的类实现的 Comparable 接口提供的比较规则进行排序

// sorted:排序,根据名字倒序
userList.stream().sorted(Comparator.comparing(User::getName).reversed()).collect(Collectors.toList()).forEach(System.out::println);
3.4、limit & skip 限制 & 跳过

limit 限制,表示截取流中的指定数量的数据(从第0开始),丢弃剩余部分
skip 跳过,表示跳过指定数量的数据,截取剩余部分

// 获取成绩的[3,5]名
dataSource.sorted((s1,s2) -> s2.score - s1.score).distinct() 
            .limit(5)
            .skip(2)
            .forEach(System.out::println);
3.5、flatMap 扁平化映射

使用 flatMap 方法的效果是,各个数组并不是分别映射成一个流,而是映射成流的内容。所有使用 map(Arrays::stream) 时生成的单个流都被合并起来,即扁平化为一个流

// 一般是用在map映射完成后,流中的数据是一个容器,而我们需要再对容器中的数据进行处理,此时使用扁平化映射
// 将字符串数组中的数据读取到流中
Stream<String> stream = Arrays.stream(s);  
// 统计字符串数组中所有出现的字符
stream.map(e -> e.split("")) 
            .flatMap(Arrays::stream)
            .distinct()
            .forEach(System.out::print);
3.6、peek 对元素进行遍历处理
// peek:对元素进行遍历处理,每个用户ID加1输出
userList.stream().peek(user -> user.setId(user.getId()+1)).forEach(System.out::println);

4、Java中的流式编程:终端操作

Stream 流执行完终端操作之后,无法再执行其他动作,否则会报状态异常,提示该流已经被执行操作或者被关闭,想要再次执行操作必须重新创建 Stream 流

一个流有且只能有一个终端操作,当这个操作执行后,流就被关闭了,无法再被操作,因此一个流只能被遍历一次,若想在遍历需要通过源数据在生成流。

终端操作的执行,才会真正开始流的遍历。如 count、collect 等

4.1、collect 收集器

collect 将流中的数据整合起来

// collect:收集器,将流转换为其他形式
Set set = userList.stream().collect(Collectors.toSet());
set.forEach(System.out::println);
System.out.println("--------------------------");
List list = userList.stream().collect(Collectors.toList());
list.forEach(System.out::println);
4.2、forEach 遍历流

forEach 遍历流中数据

// forEach:遍历流
userList.stream().forEach(user -> System.out.println(user));
userList.stream().filter(user -> "上海".equals(user.getCity())).forEach(System.out::println);
4.3、findFirst & findAny 获取流中的元素

findFirst 获取流中的一个元素,获取的是流中的首元素,在进行元素获取的时候,无论是串行流还是并行流,获取的都是首元素

// findFirst:返回第一个元素
User firstUser = userList.stream().findFirst().get();
User firstUser1 = userList.stream().filter(user -> "上海".equals(user.getCity())).findFirst().get();

findAny 获取流中的一个元素,通常是首元素,但在并行流中,获取的可能不是首元素。在进行元素获取的时候,串行流一定获取到的是流中的首元素,并行流获取到的可能是首元素,也可能不是

// findAny:将返回当前流中的任意元素
User findUser = userList.stream().findAny().get();
User findUser1 = userList.stream().filter(user -> "上海".equals(user.getCity())).findAny().get();
4.4、count 总数

count 返回流中元素总数

// count:返回流中元素总数
long count = userList.stream().filter(user -> user.getAge() > 20).count();
System.out.println(count);
4.5、sum 求和
// sum:求和
int sum = userList.stream().mapToInt(User::getId).sum();
4.6、max & min 最大 & 最小
// max:最大值
int max = userList.stream().max(Comparator.comparingInt(User::getId)).get().getId();
// min:最小值
int min = userList.stream().min(Comparator.comparingInt(User::getId)).get().getId();
4.7、reduce 聚合

reduce 将流中的数据按照一定的规则聚合起来

// reduce:将流中元素反复结合起来,得到一个值
Optional reduce = userList.stream().reduce((user, user2) -> {
      return user;
});
if(reduce.isPresent()) System.out.println(reduce.get());
4.8、allMatch & anyMatch & noneMatch

allMatch: 只有当流中所有的元素都匹配指定的规则,才会返回 true

anyMatch: 只要流中的任意数据满足指定的规则,就会返回 true

noneMatch: 只有当流中所有的元素都不满足指定的规则,才会返回 true

// allMatch:检查是否匹配所有元素
boolean matchAll = userList.stream().allMatch(user -> "北京".equals(user.getCity()));
// anyMatch:检查是否至少匹配一个元素
boolean matchAny = userList.stream().anyMatch(user -> "北京".equals(user.getCity()));
// noneMatch:检查是否没有匹配所有元素,返回 boolean
boolean nonaMatch = userList.stream().allMatch(user -> "北京".equals(user.getCity()));

5、Collect收集

Collector:结果收集策略的核心接口,具备将指定元素累加存放到结果容器中的能力;并在Collectors工具中提供了Collector接口的实现类

5.1、toList

将用户 ID 存放到 List 集合中

List<Integer> idList = userList.stream().map(User::getId).collect(Collectors.toList()) ;
5.2、toMap

将用户 ID 和 Name 以 Key-Value 形式存放到 Map 集合中

Map<Integer,String> userMap = userList.stream().collect(Collectors.toMap(User::getId,User::getName));
5.3、toSet

将用户所在城市存放到 Set 集合中

Set<String> citySet = userList.stream().map(User::getCity).collect(Collectors.toSet());
5.4、counting

符合条件的用户总数

long count = userList.stream().filter(user -> user.getId()>1).collect(Collectors.counting());
5.5、summingInt

对结果元素即用户 ID 求和

Integer sumInt = userList.stream().filter(user -> user.getId()>2).collect(Collectors.summingInt(User::getId)) ;
5.6、minBy

筛选元素中 ID 最小的用户

User maxId = userList.stream().collect(Collectors.minBy(Comparator.comparingInt(User::getId))).get() ;
5.7、joining

将用户所在城市,以指定分隔符链接成字符串

String joinCity = userList.stream().map(User::getCity).collect(Collectors.joining("||"));
5.8、groupingBy

按条件分组,以城市对用户进行分组;文章来源地址https://www.toymoban.com/news/detail-558042.html

Map<String,List<User>> groupCity = userList.stream().collect(Collectors.groupingBy(User::getCity));

到了这里,关于Java新特性:Stream流式编程的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Java中Stream流式计算的用法详解

    在Java 8之后,引入了Stream API,它是一个函数式编程的思想,其主要作用是将集合Stream化,可以使用一条语句对集合进行过滤、排序、统计等多种操作。接下来我们将详细介绍Java中Stream流式计算的用法。 Stream 接口是Java中定义的一个操作集合的高级抽象,它提供了大量的操作

    2024年02月01日
    浏览(48)
  • Java 8:Stream API 流式操作(学习)

    Java 8 中的 Stream API 是一组用于对集合数据进行处理的新特性;提供一种以声明式风格对集合进行操作的方式,简化集合的处理,使得代码更加简洁、优雅,并且能够更高效地处理数据; 这种风格将要处理的元素集合看作一种流, 流在管道中传输, 并且可以在管道的节点上进

    2024年02月10日
    浏览(34)
  • Java8新特性-流式操作

    在Java8中提供了新特性—流式操作,通过流式操作可以帮助我们对数据更快速的进行一些过滤、排序、去重、最大、最小等等操作并且内置了并行流将流划分成多个线程进行并行执行,提供更高效、快速的执行能力。接下来我们一起看看Java8为我们新增了哪些便捷呢? 目录 什

    2024年02月02日
    浏览(30)
  • JDK8新特性(一)集合之 Stream 流式操作

           首先我们应该知道:Stream流的出现,主要是用在集合的操作上。在我们日常的工作中,经常需要对集合中的元素进行相关操作。诸如:增加、删除、获取元素、遍历。         最典型的就是集合遍历了。接下来我们先举个例子来看看 JDK8 Stream流式操作出现之前,

    2024年01月23日
    浏览(28)
  • Stream流式编程,让代码变优雅

    一、引言 流式编程的概念和作用 Java 流(Stream)是一连串的元素序列,可以进行各种操作以实现数据的转换和处理。流式编程的概念基于函数式编程的思想,旨在简化代码,提高可读性和可维护性。 Java Stream 的主要作用有以下几个方面: 简化集合操作:使用传统的 for 循环或迭

    2024年02月05日
    浏览(26)
  • Java Stream 实用特性:排序、分组和 teeing

    基本数据类型排序 基本数据类型就是字符串、整型、浮点型这些,也就是要排序的列表中的元素都是这些基本类型的,比如 ListInteger 的。 下面就用一个整型列表举例说明。 正序排序 正序排序,也可以叫做按照自然顺序排序,对于整型来说就是从小到大的。 输出结果是 [0

    2024年02月03日
    浏览(40)
  • Java流式编程详细介绍

    流是从支持数据处理操作的源生成的元素序列。 流的操作特点如下: 元素序列:就像集合一样,流也提供了一个接口,可以访问特定元素类型的一组有序值 源:流会使用一个提供数据的源,如集合、数组或输入/输出资源 数据处理操作:流的数据处理功能支持类似于数据库

    2024年02月10日
    浏览(30)
  • JUC并发编程学习笔记(十二)Stream流式计算

    什么是Stream流式计算 大数据:存储+计算 集合、MySql这些的本质都是存储东西的; 计算都应该交给流来操作! 一个案例说明:函数式接口、lambda表达式、链式编程、Stream流式计算

    2024年02月05日
    浏览(36)
  • JAVA8新特性(Stream API,LocalDate,LocalDateTime)

    一. Stream API 1.1 基础 代码参数准备: 场景一:知道一个ListUser对象,如何获取ListUser的所有用户id? 场景二:知道一个ListUser对象,如何获取ListUser中年龄大于50的用户? 场景三:知道一个ListUser对象,如何按照年龄从小到小排序,从大到小排序? 场景四:知道一个ListUser对象

    2024年02月16日
    浏览(37)
  • Java 8 新特性 Stream 的使用场景(不定期更新)

    方便在写代码的过程中直接使用,好记性不如好文章,直接 CV 改了直接用。提高 办(摸)公(鱼)效(时)率(间), 不然就直接问 GPT 也不是说不行。 anyMatch :只要有一个就会返回 true 。 allMatch :所有元素都满足就返回 true。 后续将不定期更新 Stream 的骚操作使用,如果

    2024年02月05日
    浏览(33)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包