1、是什么?

  • Stream(流)是一个来自数据源的元素队列并支持聚合操作

2、能干嘛?

  • Stream流的元素是特定类型的对象,形成一个队列。
  • Java中的Stream并不会存储元素,而是按需计算。
  • 数据源,流的来源。
    • 可以是集合,数组,I/O channel, generator等。
  • 聚合操作,类似SQL语句一样的操作:
    • 比如filter, map, reduce, find, match, sorted等。
  • 和以前的Collection操作不同, Stream操作还有两个基础的特征:
    • Pipelining: 中间操作都会返回流对象本身。 这样多个操作可以串联成一个管道, 如同流式风格(fluent style)。 这样做可以对操作进行优化, 比如延迟执行(laziness)和短路( short-circuiting)。
    • 内部迭代: 以前对集合遍历都是通过Iterator或者For-Each的方式, 显式的在集合外部进行迭代, 这叫做外部迭代。 Stream提供了内部迭代的方式, 通过访问者模式(Visitor)实现。

3、怎么玩?

1、创建Stream的方式(原材料)

package com.qbb.threadpool;

import java.util.Arrays;
import java.util.List;
import java.util.stream.Stream; /**
* @author QiuQiu&LL (个人博客:https://www.cnblogs.com/qbbit)
* @version 1.0
* @date 2022-07-23 20:19
* @Description:
*/
public class Java8NewFeatureStream {
public static void main(String[] args) { // 创建Stream方式一 : 通过集合
List<Integer> list = Arrays.asList(1, 2, 3, 4, 5, 6);
// 获取串行流
Stream<Integer> stream = list.stream();
// 获取一个并行流
Stream<Integer> parallelStream = list.parallelStream(); // 创建Stream方式二 : 通过数组
String[] arr = new String[]{"a", "b", "c"};
Stream<String> arrStream = Arrays.stream(arr); // 创建Stream方式三 : 通过Stream.of()
Stream<String> streamOf = Stream.of("x", "y", "z"); // 创建Stream方式四 : 通过Stream.iterate(),创建无限流(创建无限流必须要指定范围,不然会报错的)
Stream<Integer> integerStream = Stream.iterate(0, q -> q + 1).limit(5);
integerStream.forEach(System.out::println); //生成10个随机数
Stream<Double> stream1 = Stream.generate(Math::random).limit(10);
stream1.forEach(System.out::println);
}
}

2、中间操作(车间加工)

(1)fifter(Predicate<? super T> predicate) : 过滤,保留满足条件分元素

public static void main(String[] args) {
// 创建流
List<Integer> asList = Arrays.asList(1, 2, 3, 4, 5, 6);
asList.stream()
.filter(q -> q % 2 ==0) // filter:过滤,保留符合条件的元素
.forEach(System.out::println); // forEach:内部迭代,终止操作输出每一个元素 }

(2) distinct () : 去除重复的元素

// 测试类
class User {
private String name;
private int age; public User() {
} public User(String name, int age) {
this.name = name;
this.age = age;
} @Override
public String toString() {
return "User{" +
"name='" + name + '\'' +
", age=" + age +
'}';
} public String getName() {
return name;
} public void setName(String name) {
this.name = name;
} public int getAge() {
return age;
} public void setAge(int age) {
this.age = age;
} @Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
User user = (User) o;
return age == user.age && Objects.equals(name, user.name);
} @Override
public int hashCode() {
return Objects.hash(name, age);
}
} public static void main(String[] args) {
// 创建流
List<Integer> asList = Arrays.asList(1, 2, 3, 4, 5, 6, 2, 5);
asList.stream().distinct().forEach(System.out::println); List<User> userList = new ArrayList<>();
// 测试一下对象类型
for (int i = 0; i < 5; i++) {
User user = new User("qiuqiu"+i,18+i);
userList.add(user);
}
User qiuqiu3 = new User("qiuqiu3", 21);
userList.add(qiuqiu3);
userList.stream().distinct().forEach(System.out::println);
}

(3)limit(long maxSize) : 获取指定maxSize个元素

public static void main(String[] args) {
// 创建流
List<Integer> asList = Arrays.asList(1, 2, 3, 4, 5, 6, 2, 5);
asList.stream().limit(3).forEach(System.out::println);
}

(4) skip(long n) : 跳过前n个元素

public static void main(String[] args) {
// 创建流
List<Integer> asList = Arrays.asList(1, 2, 3, 4, 5, 6, 2, 5); long count = asList.stream()
.skip(3) // 跳过前三个元素
// .findFirst() // 获取跳过操作后的第一个元素
// .findAny() // 获取跳过操作后的任意一个元素
.count(); // 获取剩余元素个数
// System.out.println("result = " + result);
System.out.println("count = " + count);
}

(5) sorted()/sorted(Comparator<? super T> comparator) : 排序

public static void main(String[] args) {
// 创建流
List<Integer> asList = Arrays.asList(4, 5, 6, 2, 1, 2, 3, 5);
// 默认排序
asList.stream().sorted().forEach(System.out::println); System.out.println("=======================================================");
// 指定比较器排序
// asList.stream().sorted((o1,o2) -> o1.compareTo(o2)).forEach(System.out::println);
asList.stream().sorted(Integer::compareTo).forEach(System.out::println);
}

(6) map :接收一个函数作为参数,该函数会被应用到每个元素上,并将其映射成一个新的元素。

public static void main(String[] args) {
// 创建流
List<Integer> asList = Arrays.asList(4, 5, 6, 2, 1, 2, 3, 5);
// map
asList.stream().map(q -> {
String str;
if(q%2 == 0){
str = q+"qiu";
}else {
str = q + "ll";
}
return str;
}).forEach(System.out::println);
}

  • 其他的一些操作
  • mapToInt(ToIntFunction<? super T> mapper)
  • mapToDouble(ToDoubleFunction<? super T> mapper)
  • mapToLong(ToLongFunction<? super T> mapper)
  • flatMapToInt(Function<? super T, ? extends IntStream> mapper)
  • flatMapToLong(Function<? super T, ? extends LongStream> mapper)
  • flatMapToDouble(Function<? super T, ? extends DoubleStream> mapper)

(7) flatMap :接收一个函数作为参数,将流中的每个值都换成另一个流,然后把所有流连接成一个流。

public static void main(String[] args) {
// 创建流
String[] arr = new String[]{"a,b,c","x,y,z"};
// flatMap
Arrays.stream(arr).flatMap(q -> {
String[] split = q.split(",");
// 把一个流拆分多个流然后又合并为一个流
Stream<String> stream = Arrays.stream(split);
return stream;
}).forEach(System.out::println);
}

(8) peek :如同于map,能得到流中的每一个元素。但map接收的是一个Function表达式,有返回值;而peek接收的是Consumer表达式,没有返回值。

public static void main(String[] args) {
// 创建流
User zs = new User("zs", 18);
User ls = new User("ls", 28); List<User> userList = Arrays.asList(zs, ls);
userList.stream()
.peek(q -> q.setAge(22))
.forEach(System.out::println);
}

当然还有其他的一些操作,这里就不一一演示了

3、终止操作

(1)匹配、聚合操作

allMatch :接收一个 Predicate 函数,当流中每个元素都符合该断言时才返回true,否则返回false

noneMatch :接收一个 Predicate 函数,当流中每个元素都不符合该断言时才返回true,否则返回false

anyMatch :接收一个 Predicate 函数,只要流中有一个元素满足该断言则返回true,否则返回false

findFirst :返回流中第一个元素

findAny :返回流中的任意元素

count :返回流中元素的总个数

max :返回流中元素最大值

min :返回流中元素最小值

forEach: 遍历流中的元素

forEachOrdered: 并行流下遍历流中的元素保证顺序

public static void main(String[] args) {
// 创建流
List<Integer> asList = Arrays.asList(4, 5, 6, 2, 1, 2, 3, 5); boolean allMatch = asList.stream().allMatch(q -> q > 0);
System.out.println("allMatch = " + allMatch); boolean noneMatch = asList.stream().noneMatch(q -> q < 0);
System.out.println("noneMatch = " + noneMatch); boolean anyMatch = asList.stream().anyMatch(q -> q % 2 == 0);
System.out.println("anyMatch = " + anyMatch); Integer findFirst = asList.stream().findFirst().get();
System.out.println("findFirst = " + findFirst); Integer findAny = asList.stream().findAny().get();
System.out.println("findAny = " + findAny); // long count = asList.stream().count();
long count = asList.size();
System.out.println("count = " + count); Integer max = asList.stream().max(Comparator.comparingInt(o -> o)).get();
System.out.println("max = " + max); Integer min = asList.stream().min(Integer::compareTo).get();
System.out.println("min = " + min); String str = "my name is qiuqiu";
Stream.of(str.split(" ")).parallel().forEach(System.out::println);
System.out.println();
Stream.of(str.split(" ")).parallel().forEachOrdered(System.out::println); }

(2) 规并操作

Optional<T> reduce(BinaryOperator<T> accumulator) :第一次执行时,accumulator函数的第一个参数为流中的第一个元素,第二个参数为流中元素的第二个元素;第二次执行时,第一个参数为第一次函数执行的结果,第二个参数为流中的第三个元素;依次类推。

T reduce(T identity, BinaryOperator<T> accumulator) :流程跟上面一样,只是第一次执行时,accumulator函数的第一个参数为identity,而第二个参数为流中的第一个元素。

<U> U reduce(U identity,BiFunction<U, ? super T, U> accumulator,BinaryOperator<U> combiner) :在串行流(stream)中,该方法跟第二个方法一样,即第三个参数combiner不会起作用。在并行流(parallelStream)中,我们知道流被fork join出多个线程进行执行,此时每个线程的执行流程就跟第二个方法reduce(identity,accumulator)一样,而第三个参数combiner函数,则是将每个线程的执行结果当成一个新的流,然后使用第一个方法reduce(accumulator)流程进行规约。

public static void main(String[] args) {
// 创建流
List<Integer> asList = Arrays.asList(1, 2, 3, 4, 5);
Integer one = asList.stream().reduce(Integer::sum).get();
System.out.println("one = " + one); Integer two = asList.stream().reduce(100, Integer::sum);
System.out.println("two = " + two); Integer three = asList.parallelStream().reduce(100,
Integer::sum,
(x, y) -> x * y);
System.out.println("three = " + three);
}

(3) 收集操作

collect :接收一个Collector实例,将流转化为其他形式,常用的List、Set、Map、Collection。

  • 内部通过Collectors这个类进行相应的操作

(4) Collectors相关操作

toCollection toList() toSet() toMap : 将输入元素累积到一个集合中
public static void main(String[] args) {
List<Integer> list = Arrays.asList(1, 2, 3, 4, 5, 6, 7); list.replaceAll(q -> q > 5 ? q + 10 : q);
System.out.println("list = " + list);
list.sort((o1, o2) -> o1 - o2);
// 转Collection
Collection<Integer> collection = list.parallelStream().collect(Collectors.toCollection(HashSet::new));
// 转List
List<Integer> integerList = list.parallelStream().collect(Collectors.toList());
// 转Set
Set<Integer> set = list.parallelStream().collect(Collectors.toSet());
// 转Map
Map<Integer, Integer> map = list.parallelStream().collect(Collectors.toMap(item -> item, integer -> integer));
}
joining : 连接字符串
// joining
List<String> list = Arrays.asList("a", "b", "c", "d", "e", "f", "g");
String result = list.parallelStream().collect(Collectors.joining(",", "[", "]"));
System.out.println("result = " + result);
mapping/flatMapping : 它将Function应用于输入元素,然后将它们累积到给定的Collector
Set<String> setStr = Stream.of("a", "a", "b")
.collect(Collectors.mapping(String::toUpperCase, Collectors.toSet()));
System.out.println(setStr); // [A, B] Set<String> setStr1 = Stream.of("a", "a", "b")
.collect(Collectors.flatMapping(s -> Stream.of(s.toUpperCase()), Collectors.toSet()));
System.out.println(setStr1); // [A, B]
collectingAndThen : 返回一个收集器,该收集器将输入元素累积到给定的收集器中,然后执行其他完成功能
List<String> strList2 = Lists.newArrayList("1", "2", "10", "100", "20", "999");

List<String> unmodifiableList = strList2.parallelStream()
.collect(Collectors.collectingAndThen(Collectors.toList(), Collections::unmodifiableList));
System.out.println(unmodifiableList); // [1, 2, 10, 100, 20, 999]
counting : 计数
Long evenCount = Stream.of(1, 2, 3, 4, 5).filter(x -> x % 2 == 0).collect(Collectors.counting());
System.out.println(evenCount); // 2
minBy : 根据给定的比较器返回最小元素
Optional<Integer> min = Stream.of(1, 2, 3, 4, 5).collect(Collectors.minBy((x, y) -> x - y));
System.out.println(min); // Optional[1]
maxBy : 它根据给定的比较器返回最大元素
Optional<Integer> max = Stream.of(1, 2, 3, 4, 5).collect(Collectors.maxBy((x, y) -> x - y));
System.out.println(max); // Optional[5]
summingInt/summingLong/summingDouble : 求总和
List<String> strList3 = Arrays.asList("1", "2", "3", "4", "5");
Integer sum = strList3.parallelStream().collect(Collectors.summingInt(Integer::parseInt));
System.out.println(sum); // 15 Long sumL = Stream.of("12", "23").collect(Collectors.summingLong(Long::parseLong));
System.out.println(sumL); // 35 Double sumD = Stream.of("1e2", "2e3").collect(Collectors.summingDouble(Double::parseDouble));
System.out.println(sumD); // 2100.0
averagingInt/averagingLong/averagingDouble : 求平均值
List<String> strList4 = Arrays.asList("1", "2", "3", "4", "5");
Double average = strList4.parallelStream().collect(Collectors.averagingInt(Integer::parseInt));
System.out.println(average); // 3.0 Double averageL = Stream.of("12", "23").collect(Collectors.averagingLong(Long::parseLong));
System.out.println(averageL); // 17.5 Double averageD = Stream.of("1e2", "2e3").collect(Collectors.averagingDouble(Double::parseDouble));
System.out.println(averageD); // 1050.0
groupingBy : 分组
Map<Integer, List<Integer>> mapGroupBy = Stream.of(1, 2, 3, 4, 5, 4, 3).collect(Collectors.groupingBy(x -> x * 10));
System.out.println(mapGroupBy); // {50=[5], 20=[2], 40=[4, 4], 10=[1], 30=[3, 3]}
groupingByConcurrent : 分组,是并发和无序的
Map<Integer, List<Integer>> mapGroupBy = Stream.of(1, 2, 3, 4, 5, 4, 3).collect(Collectors.groupingByConcurrent(x -> x * 10));
System.out.println(mapGroupBy); // {50=[5], 20=[2], 40=[4, 4], 10=[1], 30=[3, 3]}
partitioningBy : 返回一个Collector,它根据Predicate对输入元素进行分区,并将它们组织成Map <Boolean,List >
Map<Boolean, List<Integer>> mapPartitionBy = Stream.of(1, 2, 3, 4, 5, 4, 3).collect(Collectors.partitioningBy(x -> x % 2 == 0));
System.out.println(mapPartitionBy); // {false=[1, 3, 5, 3], true=[2, 4, 4]}
BinaryOperator : 返回一个收集器,它在指定的BinaryOperator下执行其输入元素的减少。这主要用于多级缩减,例如使用groupingBy()和partitioningBy()方法指定下游收集器
Map<Boolean, Optional<Integer>> reducing = Stream.of(1, 2, 3, 4, 5, 4, 3).collect(Collectors.partitioningBy(
x -> x % 2 == 0, Collectors.reducing(BinaryOperator.maxBy(Comparator.comparing(Integer::intValue)))));
System.out.println(reducing); // {false=Optional[5], true=Optional[4]}
summarizingInt : 返回统计数据:min, max, average, count, sum
IntSummaryStatistics summarizingInt = Stream.of("12", "23", "35")
.collect(Collectors.summarizingInt(Integer::parseInt));
System.out.println(summarizingInt);
//IntSummaryStatistics{count=3, sum=70, min=12, average=23.333333, max=35}

Java8新特性Stream流的更多相关文章

  1. 这可能是史上最好的 Java8 新特性 Stream 流教程

    本文翻译自 https://winterbe.com/posts/2014/07/31/java8-stream-tutorial-examples/ 作者: @Winterbe 欢迎关注个人微信公众 ...

  2. Java8新特性 Stream流式思想(二)

    如何获取Stream流刚开始写博客,有一些不到位的地方,还请各位论坛大佬见谅,谢谢! package cn.com.zq.demo01.Stream.test01.Stream; import org ...

  3. Java8新特性Stream流应用示例

    Java8新特性介绍 过滤集合 List<String> newList = list.stream().filter(item -> item != null).collect(C ...

  4. java8 新特性Stream流的应用

    作为一个合格的程序员,如何让代码更简洁明了,提升编码速度尼. 今天跟着我一起来学习下java 8  stream 流的应用吧. 废话不多说,直入正题. 考虑以下业务场景,有四个人员信息,我们需要根据性 ...

  5. Java8新特性 Stream流式思想(一)

    遍历及过滤集合中的元素使用传统方式遍历及过滤集合中的元素package cn.com.zq.demo01.Stream.test01.Stream; import java.util.ArrayLis ...

  6. Java8新特性 Stream流式思想(三)

    Stream接口中的常用方法 forEach()方法package cn.com.cqucc.demo02.StreamMethods.Test02.StreamMethods; import jav ...

  7. Java8 新特性 —— Stream 流式编程

    本文部分摘自 On Java 8 流概述 集合优化了对象的存储,大多数情况下,我们将对象存储在集合是为了处理他们.使用流可以帮助我们处理对象,无需迭代集合中的元素,即可直接提取和操作元素,并添加了很多 ...

  8. Java8新特性——stream流

    一.基本API初探 package java8.stream; import java.util.Arrays; import java.util.IntSummaryStatistics; impo ...

  9. java8 新特性 Stream流 分组 排序 过滤 多条件去重

    private static List<User> list = new ArrayList<User>(); public static void main(String[] ...

  10. Java8 新特性 Stream 无状态中间操作

    无状态中间操作 Java8 新特性 Stream 练习实例 中间无状态操作,可以在单个对单个的数据进行处理.比如:filter(过滤)一个元素的时候,也可以判断,比如map(映射)... 过滤 fil ...

随机推荐

  1. 如何get一个终身免费续期的定制数字人?

    想拥有一个"数字分身" 吗?给你一个终身免费续期的特权. 定制周期长?训练.运营成本高?成片效果生硬?无法应用于实际场景? 随着AIGC技术的快速发展,虚拟数字人的生成效率不断提高 ...

  2. 关于使用uniapp时Android 离线打包的注意事项

    Android 离线打包 文档地址: https://nativesupport.dcloud.net.cn/AppDocs/usesdk/android 注意事项: 添加权限,需要将 uniapp ...

  3. Machine Learning for NetFlow Anomaly Detection With Human-Readable Annotations 笔记

    Machine Learning for NetFlow Anomaly Detection With Human-Readable Annotations 关键摘要 我们开发了一个复杂企业网络中的异 ...

  4. 彻底弄懂ip掩码中的网络地址、广播地址、主机地址

    本文为博主原创,转载请注明出处: 概念理解: IP掩码(或子网掩码)用于确定一个IP地址的网络部分和主机部分.它是一个32位的二进制数字,与IP地址做逻辑与运算,将IP地址划分为网络地址和主机地址两部 ...

  5. 教育法学期末考试02MOOC

    期末考试 返回 期末考试试卷为客观题,总分为100分,占课程成绩的40%.其中包含16道单选题,2道多选题.共18道题.单选题每道5分,多选题每道10分,限时90分钟完成.  倒计时:  01:21: ...

  6. C#/.NET/.NET Core优秀项目和框架精选(2023年10月更新,项目分类已整理完成欢迎大家踊跃提交PR一起完善让优秀的项目和框架不被埋没)

    前言 帮助开发者发现功能强大.性能优越.创新前沿.简单易用的C#/.NET/.NET Core优秀项目和框架,无论你是寻找灵感.学习新技术.改进代码质量,还是想拓展自己的技术视野,都能为你提供有价值的 ...

  7. DRTREE - Dynamically-Rooted Tree 题解

    DRTREE - Dynamically-Rooted Tree 本题建议评蓝. 思路: 题目就是要对一颗不定根树求子树权值和. 这题不带修,如果带修难度会增加一点,就跟 遥远的国度 差不多. 首先分 ...

  8. Hall定理(霍尔定理)证明及推广

    引言 网络上有许多Hall定理的证明,但是对于Hall定理的几个推广的介绍却少之又少,因此本文来简单介绍一下 注:为了使这篇文章看起来简单易懂,本文将不会使用图论语言,会图论的朋友们可以自行翻译为图论 ...

  9. MongoDB 中的锁分析

    MongoDB 中的锁 前言 MongoDB 中锁的类型 锁的让渡释放 常见操作使用的锁类型 如果定位 MongoDB 中锁操作 1.查询运行超过20S 的请求 2.批量删除请求大于 20s 的请求 ...

  10. List、Set与 Map

    目录 1. List接口和常用方法 1.1 List接口基本介绍 1.2 List接口的三种遍历方式 2. ArrayList 2.1 注意事项 2.2 ArrayList的底层操作机制源码分析(重点 ...