• Java8中有两大最为重要的改变。第一个是 Lambda 表达式;另外一个则是 Stream API。
  • Stream API ( java.util.stream) 把真正的函数式编程风格引入到Java中。这是目前为止对Java类库最好的补充,因为Stream API可以极大提供Java程序员的生产力,让程序员写出高效率、干净、简洁的代码。

Stream 是 Java8 中处理集合的关键抽象概念,它可以指定你希望对集合进行的操作,可以执行非常复杂的查找、过滤和映射数据等操作。 使用Stream API 对集合数据进行操作,就类似于使用 SQL 执行的数据库查询。也可以使用 Stream API 来并行执行操作。简言之,Stream API 提供了一种高效且易于使用的处理数据的方式。

什么是Stream

Stream 是数据渠道,用于操作数据源(集合、数组等)所生成的元素序列。

Stream 和 Collection 集合的区别:Collection 是一种静态的内存数据结构,讲的是数据,而 Stream 是有关计算的,讲的是计算。前者是主要面向内存,存储在内存中,后者主要是面向 CPU,通过 CPU 实现计算。

注意:

①Stream 自己不会存储元素。

②Stream 不会改变源对象。相反,他们会返回一个持有结果的新Stream。

③Stream 操作是延迟执行的。这意味着他们会等到需要结果的时候才执行。即一旦执行终止操作,就执行中间操作链,并产生结果。

④ Stream一旦执行了终止操作,就不能再调用其它中间操作或终止操作了。

Stream操作的三个步骤

1- 创建 Stream 一个数据源(如:集合、数组),获取一个流

2- 中间操作 每次处理都会返回一个持有结果的新Stream,即中间操作的方法返回值仍然是Stream类型的对象。因此中间操作可以是个操作链,可对数据源的数据进行n次处理,但是在终结操作前,并不会真正执行。

3- 终止操作(终端操作) 终止操作的方法返回值类型就不再是Stream了,因此一旦执行终止操作,就结束整个Stream操作了。一旦执行终止操作,就执行中间操作链,最终产生结果并结束Stream。

创建Stream实例

方式一:通过集合

Java8 中的 Collection 接口被扩展,提供了两个获取流的方法:

  • default Stream stream() : 返回一个顺序流
  • default Stream parallelStream() : 返回一个并行流
    //创建 Stream方式一:通过集合
@Test
public void test1(){
// default Stream<E> stream() : 返回一个顺序流
List<Integer> list = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8);
Stream<Integer> stream = list.stream();
// default Stream<E> parallelStream() : 返回一个并行流
Stream<Integer> integerStream = list.parallelStream();
}

方式二:通过数组

Java8 中的 Arrays 的静态方法 stream() 可以获取数组流:

  • static Stream stream(T[] array): 返回一个流
  • public static IntStream stream(int[] array)
  • public static LongStream stream(long[] array)
  • public static DoubleStream stream(double[] array)
    //创建 Stream方式二:通过数组
@Test
public void test2(){
//调用Arrays类的static <T> Stream<T> stream(T[] array): 返回一个流
String[] array = {"tom", "jack"};
Stream<String> stream = Arrays.stream(array);
}

方式三:通过Stream的of()

可以调用Stream类静态方法 of(), 通过显示值创建一个流。它可以接收任意数量的参数。

  • public static Stream of(T... values) : 返回一个流
    //创建 Stream方式三:通过Stream的of()
@Test
public void test3(){
Stream<Integer> stream = Stream.of(1, 2, 3, 4, 5);
}

一系列中间操作

多个中间操作可以连接起来形成一个流水线,除非流水线上触发终止操作,否则中间操作不会执行任何的处理!而在终止操作时一次性全部处理,称为“惰性求值”。

1-筛选与切片

方 法 描 述
filter(Predicatep) 接收 Lambda , 从流中排除某些元素
distinct() 筛选,通过流所生成元素的 hashCode() 和 equals() 去除重复元素
limit(long maxSize) 截断流,使其元素不超过给定数量
skip(long n) 跳过元素,返回一个扔掉了前 n 个元素的流。
若流中元素不足 n 个,则返回一个空流。与 limit(n) 互补

2-映 射

方法 描述
map(Function f) 接收一个函数作为参数,该函数会被应用到每个元素上,并将其映射成一个新的元素。
mapToDouble(ToDoubleFunction f) 接收一个函数作为参数,该函数会被应用到每个元素上,产生一个新的 DoubleStream。
mapToInt(ToIntFunction f) 接收一个函数作为参数,该函数会被应用到每个元素上,产生一个新的 IntStream。
mapToLong(ToLongFunction f) 接收一个函数作为参数,该函数会被应用到每个元素上,产生一个新的 LongStream。
flatMap(Function f) 接收一个函数作为参数,将流中的每个值都换成另一个流,然后把所有流连接成一个流

3-排序

方法 描述
sorted() 产生一个新流,其中按自然顺序排序
sorted(Comparator com) 产生一个新流,其中按比较器顺序排序
package com.mcode.stream;

import org.junit.Test;

import java.util.Arrays;
import java.util.List;
import java.util.stream.Stream; /**
* ClassName: StreamTest1
* Package: com.mcode.stream
* Description:
*
* @Author: robin
* @Create: 2023/11/5 - 12:23 AM
* @Version: v1.0
*/
public class StreamTest1 { //1-筛选与切片
@Test
public void test1() {
// filter(Predicate p)——接收 Lambda , 从流中排除某些元素。
Stream<Integer> stream = Stream.of(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
stream.filter(n-> n>5).forEach(System.out::println); System.out.println();
// limit(n)——截断流,使其元素不超过给定数量。
Stream<Integer> stream1 = Stream.of(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
stream1.limit(5).forEach(System.out::println); System.out.println();
// skip(n) —— 跳过元素,返回一个扔掉了前 n 个元素的流。若流中元素不足 n 个,则返回一个空流。与 limit(n) 互补
Stream<Integer> stream2 = Stream.of(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
stream2.skip(5).forEach(System.out::println);
System.out.println();
// distinct()——筛选,通过流所生成元素的 hashCode() 和 equals() 去除重复元素
List<Integer> list = Arrays.asList(1, 1,2, 2,3, 4, 5, 6, 7, 8, 9, 10);
list.stream().distinct().forEach(System.out::println); } //映射
@Test
public void test2() {
//map(Function f)——接收一个函数作为参数,将元素转换成其他形式或提取信息,该函数会被应用到每个元素上,并将其映射成一个新的元素。
//练习:转换为大写
List<String> list = Arrays.asList("aa", "bb", "cc", "dd");
list.stream().map(String::toUpperCase).forEach(System.out::println); //mapToDouble接收一个函数作为参数,该函数会被应用到每个元素上,产生一个新的 DoubleStream。
List<Integer> list1 = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
list1.stream().mapToDouble(n-> (double)n).forEach(System.out::println); //flatMap接收一个函数作为参数,将流中的每个值都换成另一个流,然后把所有流连接成一个流
Stream.of("hello","world","java").flatMap(t-> Stream.of(t.split("|")))
.forEach(System.out::println);
} //3-排序
@Test
public void test3() {
//sorted()——自然排序
Integer[] arr = new Integer[]{345,3,64,3,46,7,3,34,65,68};
String[] arr1 = new String[]{"GG","DD","MM","SS","JJ"}; Arrays.stream(arr).sorted().forEach(System.out::println); //sorted(Comparator com)——定制排序
Arrays.stream(arr).sorted((x,y)->(x > y) ? -1 : ((x == y) ? 0 : 1) ).forEach(System.out::println); }
}

终止操作

  • 终端操作会从流的流水线生成结果。其结果可以是任何不是流的值,例如:List、nteger,甚至是 void 。
  • 流进行了终止操作后,不能再次使用。
方法 描述
allMatch(Predicate p) 检查是否匹配所有元素
anyMatch(Predicate p) 检查是否至少匹配一个元素
noneMatch(Predicate p) 检查是否没有匹配所有元素
findFirst() 返回第一个元素
findAny() 返回当前流中的任意元素
count() 返回流中元素总数
max(Comparator c) 返回流中最大值
min(Comparator c) 返回流中最小值
forEach(Consumer c) 内部迭代(使用 Collection 接口需要用户去做迭代,称为外部迭代。
相反,Stream API 使用内部迭代——它帮你把迭代做了)

2-归约

方法 描述
reduce(T identity, BinaryOperator b) 可以将流中元素反复结合起来,得到一个值。返回 T
reduce(BinaryOperator b) 可以将流中元素反复结合起来,得到一个值。返回 Optional

备注:map 和 reduce 的连接通常称为 map-reduce 模式,因 Google 用它来进行网络搜索而出名。

3-收集

方 法 描 述
collect(Collector c) 将流转换为其他形式。接收一个 Collector接口的实现,
用于给Stream中元素做汇总的方法

Collector 接口中方法的实现决定了如何对流执行收集的操作(如收集到 List、Set、Map)。

另外, Collectors 实用类提供了很多静态方法,可以方便地创建常见收集器实例,具体方法与实例如下表:

方法 返回类型 作用
toList Collector<T, ?, List> 把流中元素收集到List

List emps= list.stream().collect(Collectors.toList());

方法 返回类型 作用
toSet Collector<T, ?, Set> 把流中元素收集到Set

Set emps= list.stream().collect(Collectors.toSet());

方法 返回类型 作用
toCollection Collector<T, ?, C> 把流中元素收集到创建的集合

Collection emps =list.stream().collect(Collectors.toCollection(ArrayList::new));

方法 返回类型 作用
counting Collector<T, ?, Long> 计算流中元素的个数

long count = list.stream().collect(Collectors.counting());

方法 返回类型 作用
summingInt Collector<T, ?, Integer> 对流中元素的整数属性求和

int total=list.stream().collect(Collectors.summingInt(Employee::getSalary));

方法 返回类型 作用
averagingInt Collector<T, ?, Double> 计算流中元素Integer属性的平均值

double avg = list.stream().collect(Collectors.averagingInt(Employee::getSalary));

方法 返回类型 作用
summarizingInt Collector<T, ?, IntSummaryStatistics> 收集流中Integer属性的统计值。如:平均值

int SummaryStatisticsiss= list.stream().collect(Collectors.summarizingInt(Employee::getSalary));

方法 返回类型 作用
joining Collector<CharSequence, ?, String> 连接流中每个字符串

String str= list.stream().map(Employee::getName).collect(Collectors.joining());

方法 返回类型 作用
maxBy Collector<T, ?, Optional> 根据比较器选择最大值

Optionalmax= list.stream().collect(Collectors.maxBy(comparingInt(Employee::getSalary)));

方法 返回类型 作用
minBy Collector<T, ?, Optional> 根据比较器选择最小值

Optional min = list.stream().collect(Collectors.minBy(comparingInt(Employee::getSalary)));

方法 返回类型 作用
reducing Collector<T, ?, Optional> 从一个作为累加器的初始值开始,利用BinaryOperator与流中元素逐个结合,从而归约成单个值

int total=list.stream().collect(Collectors.reducing(0, Employee::getSalar, Integer::sum));

方法 返回类型 作用
collectingAndThen Collector<T,A,RR> 包裹另一个收集器,对其结果转换函数

int how= list.stream().collect(Collectors.collectingAndThen(Collectors.toList(), List::size));

方法 返回类型 作用
groupingBy Collector<T, ?, Map<K, List>> 根据某属性值对流分组,属性为K,结果为V

Map<Emp.Status, List> map= list.stream().collect(Collectors.groupingBy(Employee::getStatus));

方法 返回类型 作用
partitioningBy Collector<T, ?, Map<Boolean, List>> 根据true或false进行分区
package com.mcode.stream;

import org.junit.Test;

import javax.lang.model.element.VariableElement;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream; /**
* ClassName: StreamTest2
* Package: com.mcode.stream
* Description:
*
* @Author: robin
* @Create: 2023/11/5 - 01:03 AM
* @Version: v1.0
*/
public class StreamTest2 {
//1-匹配与查找
@Test
public void test1(){
// allMatch(Predicate p)——检查是否匹配所有元素。
boolean b = Stream.of(1, 2, 3, 4, 5).allMatch(n -> n > 4);
System.out.println(b); // anyMatch(Predicate p)——检查是否至少匹配一个元素。
boolean b1 = Stream.of(1, 2, 3, 4, 5).anyMatch(n -> n > 4);
System.out.println(b1); // findFirst——返回第一个元素
Optional<Integer> first = Stream.of(1, 2, 3, 4, 5).findFirst();
System.out.println(first.get()); } @Test
public void test2(){
// count——返回流中元素的总个数
long count = Stream.of(1, 2, 3, 4, 5).count();
System.out.println(count); // max(Comparator c)——返回流中最大值
Optional<Integer> max = Arrays.asList(1, 2, 3, 4, 5).stream().max(Integer::compare);
System.out.println(max.get()); // min(Comparator c)——返回流中最小值
Optional<Integer> min = Arrays.asList(1, 2, 3, 4, 5).stream().min(Integer::compareTo);
System.out.println(min.get()); // forEach(Consumer c)——内部迭代
Arrays.asList(1, 2, 3, 4, 5).stream().forEach(System.out::println); } //2-归约
@Test
public void test3(){
// reduce(T identity, BinaryOperator)——可以将流中元素反复结合起来,得到一个值。返回 T
// 练习1:计算1-10的自然数的和
Integer reduce = Stream.of(1, 2, 3, 4, 5).reduce(0, (x, y) -> x + y);
System.out.println(reduce); } //3-收集
@Test
public void test4(){
// collect(Collector c)——将流转换为其他形式。接收一个 Collector接口的实现,用于给Stream中元素做汇总的方法
List<Integer> collect = Arrays.asList(1, 2, 3, 4, 5).stream().collect(Collectors.toList());
System.out.println(collect);
Set<Integer> collect1 = Stream.of(1, 2,3, 3, 4,5).collect(Collectors.toSet());
System.out.println(collect1);
Map<Integer, List<Integer>> collect2 = Stream.of(1,2, 2, 3, 4, 5).collect(Collectors.groupingBy(x -> x));
System.out.println(collect2);
}
}

Java系列:Java8 新特性:强大的 Stream API(创建 Stream、中间操作、终止操作)的更多相关文章

  1. 【Java】Java8新特性

    文章目录 Java8新特性 Lambda表达式的使用 语法格式一:无参,无返回值 语法格式二:Lambda 需要一个参数,但是没有返回值. 语法格式三:数据类型可以省略,因为可由编译器推断得出,称为& ...

  2. Java基础-Java8新特性

    一.Lambda表达式 在了解 Lambda 之前,首先回顾以下Java的方法. Java的方法分为实例方法,例如:Integer的equals()方法: public final class Int ...

  3. [Java SE]Java8新特性——默认方法

    1 简述 默认方法就是接口可以有实现方法,而且可以不需要实现类去实现其方法 默认方法(default void hello()) := 一个在接口里面有了一个(默认)实现的方法 1. 子类优先继承父类 ...

  4. java基础---java8 新特性

    1. 函数式接口 函数式接口主要指只包含一个抽象方法的接口,如:java.lang.Runnable(java1.0).java.util.Comparator接口(java1.4)等. Java8提 ...

  5. java8新特性七-Date Time API

    Java 8通过发布新的Date-Time API (JSR 310)来进一步加强对日期与时间的处理. 在旧版的 Java 中,日期时间 API 存在诸多问题,其中有: 非线程安全 − java.ut ...

  6. Java8新特性--日期和时间API

    如何正确处理时间 现实生活的世界里,时间是不断向前的,如果向前追溯时间的起点,可能是宇宙出生时,又或是是宇宙出现之前, 但肯定是我们目前无法找到的,我们不知道现在距离时间原点的精确距离.所以我们要表示 ...

  7. java8新特性学习笔记

    目录 1.速度更快 2.Lambda表达式 2.1.匿名内部类的Lambda转换 2.2.java8内置的四大核心函数式接口 2.3.方法引用和构造器 2.3.1.方法引用 2.3.2.构造器引用 2 ...

  8. Java8 新特性 Data Time API

    Java8新的日期类型 在Java8以前,Date日期API对我们非常的不友好,它无法表示日期,只能以毫秒的精试来表示时间,并且可以修改,他的线程还不是安全的.所以Java8中引入了全新的日期和时间A ...

  9. 夯实Java基础系列21:Java8新特性终极指南

    本系列文章将整理到我在GitHub上的<Java面试指南>仓库,更多精彩内容请到我的仓库里查看 https://github.com/h2pl/Java-Tutorial 喜欢的话麻烦点下 ...

  10. Java系列 - 用Java8新特性进行Java开发太爽了

    本人博客文章网址:https://www.peretang.com/using-java8s-new-features-to-coding-is-awesome/ 前言 从开始写博客到现在已经过去3个 ...

随机推荐

  1. 服务端apk打包教程

    本文我将给大家介绍一个 apk 打包工具 VasDolly 的使用介绍.原理以及如何在服务端接入 VasDolly 进行服务端打渠道包操作. 使用介绍 VasDolly 是一个快速多渠道打包工具,同时 ...

  2. 原来TypeScript中的接口和泛型这么好理解

    "接口"和"泛型"是 TypeScript 相比于 JavaScript 新增的内容,都用于定义数据类型 前面两篇文章总结了TypeScript中的 类型注解. ...

  3. Mysql高级7-存储过程

    一.介绍 存储过程是事先经过编译并存储在数据库中的一段sql语句的集合,调用存储过程可以简化应用开发人员的很多工作,减少数据在数据库和应用服务器之间的传输,对于提高数据处理的效率是有好处的.存储过程思 ...

  4. 论文解读(ECACL)《ECACL: A Holistic Framework for Semi-Supervised Domain Adaptation》

    Note:[ wechat:Y466551 | 付费咨询,非诚勿扰 ] 论文信息 论文标题:ECACL: A Holistic Framework for Semi-Supervised Domain ...

  5. vlak

    2023-7-14 题目 luogu题目传送门 题目描述 Nina 和 Emilija 正在玩一个特殊的游戏.这个游戏是在一张最开始为空白的纸上进行的.在每一个人的行动回合内,这个人会在这张纸上当前的 ...

  6. 【JMeter】使用BeanShell写入内容到文件

    使用BeanShell写入内容到文件 目录 使用BeanShell写入内容到文件 一.前言 二.提取 三.写入 一.前言 ​ 在我们日常工作中,可能会遇到需要将请求返回的数据写入到文件中.在我们使用J ...

  7. 深入理解MySQL:数据类型、查询优化、索引、事务处理和数据备份与恢复

    摘要: MySQL 是一种常用的关系型数据库管理系统,对于开发者和数据库管理员来说,掌握 MySQL 的关键概念和最佳实践非常重要.本文将围绕 MySQL 的数据类型.查询优化.索引.事务处理以及数据 ...

  8. JOIN 关联表中 ON、WHERE 后面跟条件的区别

    SQL中join连接查询时条件放在on后与where后的区别 数据库在通过连接两张或多张表来返回记录时,都会生成一张中间的临时表,然后再将这张临时表返回给用户. 在使用left jion时,on和wh ...

  9. 通过WinSW部署JAR包为windows服务

    通过WinSW部署JAR包为windows服务 背景 使用 Java 编写了一些有用的工具,因为不方便部署到服务器上,所以需要把 Java 生成的 jar 包在本地 Windows 上部署. 查阅了几 ...

  10. MindSponge分子动力学模拟——定义一个分子系统(2023.08)

    技术背景 在前面两篇文章中,我们分别介绍了分子动力学模拟软件MindSponge的软件架构和安装与使用教程.这里我们进入到实用化阶段,假定大家都已经在本地部署好了基于MindSpore的MindSpo ...