什么是Stream?

Stream是JDK8 API的新成员,它允许以声明性方式处理数据集合

特点

  1. 代码简洁: 函数式编程写出的代码简洁且意图明确,使用stream接口让你从此告别for循环
  2. 多核友好: Java函数式编程使得编写并行程序从未如此简单,你需要的全部就是调用一下方法

为什么要使用Stream API?

  • 实际开发中,项目中多数数据源都来自于MySQL,Oracle等.但现在数据源可以更多了,有MongoDB,Redis等,而这些NoSQL的数据就需要Java层面去处理

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

    注意:

    1. Stream自己不会存储元素
    2. Stream不会改变源对象.相反,他们会返回一个持有结果的新Stream
    3. Stream操作是延迟执行的.这意味着他们会等到需要结果的时候才执行

步骤

  1. 创建Stream

    一个数据源(集合,数组等),获取一个流

  2. 中间操作

    一个中间操作链,对数据源的数据进行处理

  3. 终止操作

    一旦执行终止操作,就执行中间操作链,并产生结果.之后,不会再被使用

Stream的实例化

/**
* @PROJECT_NAME: myTest
* @DESCRIPTION: Stream的方法测试
* @USER: 罗龙达
* @DATE: 2021/2/21 2:33
*/
public class streamTest { @Test
public void createStream(){
List<String> strings = Arrays.asList("abc", "", "bc", "efg", "abcd", "", "jk");
//1. 通过集合创建stream -- 返回一个顺序流
Stream<String> listStream = strings.stream(); //返回一个并行流
Stream<String> paraStream = strings.parallelStream(); //2. 通过数组创建stream
IntStream arrStream = Arrays.stream(new int[]{1, 3, 45, 6, 877, 12}); //3. 通过Stream的of()方法
Stream<Integer> integerStream = Stream.of(1, 3, 5, 7, 9); //4. 创建无限流
Stream.iterate(0,t -> t+2).limit(10).forEach(System.out::println); //5. 生成
Stream.generate(Math::random).limit(10).forEach(System.out::println);
}
}

中间操作的部分API测试

    @Test
public void InOperationTest() {
List<String> strings = Arrays.asList("abc", "", "bc", "efg", "abcd", "abc", "jk");
//1. 通过集合创建stream -- 返回一个顺序流
Stream<String> listStream = strings.stream();
System.out.println("-----------测试filter--------------");
/**
* filter(Predicate predicate) -- 接收lambda,从流中排除某些元素
* 查询列表中不为null的元素
*/
//
listStream.filter(s -> !s.equals("")).forEach(System.out::println);
System.out.println("--------------测试limit------------");
/**
*limit(n) -- 截断流,使元素不超过给定数量
*/
strings.stream().limit(3).forEach(System.out::println); System.out.println("-------------测试skip--------------");
/**
*skip(n) -- 跳过元素,返回一个扔掉了前n个元素的流,如果流中元素不足n个,则返回一个空流
*/
strings.stream().skip(3).forEach(System.out::println); System.out.println("------------测试distinct-----------");
/**
*distinct() -- 筛选,通过流所产生元素的hashCode()和equals()去除重复元素
*/
strings.stream().distinct().forEach(System.out::println);
}

Map映射API的部分测试

    @Test
public void mapTest(){
System.out.println("----------------将字符串转换成大写---------------");
List<String> strings = Arrays.asList("aaa", "bb", "cccc", "d","eeeee","ff");
/**
* 接受一个函数作为参数,将元素转换成其他形式或提取信息,该函数会被应用到每个元素上,并将其映射成一个新的元素
*/
strings.stream().map(String::toUpperCase).forEach(System.out::println);
System.out.println("------------字符串长度大于3的元素的大写-----------"); /**
* 返回字符串长度大于3的元素的大写
*/
strings.stream().filter(s -> s.length() >3).map(String::toUpperCase).forEach(System.out::println); /**
* flatMap(Function f) -- 接收一个函数作为参数,将流中的每个值都换成另一个流,然后把所有流连接成一个流。
*/
strings.stream().flatMap(streamTest::fromStringToStream).forEach(System.out::println);
} //将字符串中的多个字符构成的集合转换为对应的流
public static Stream<Character> fromStringToStream(String s){
ArrayList<Character> list = new ArrayList<>();
for (char c : s.toCharArray()) {
list.add(c);
}
return list.stream();
}

map与flatMap的区别

  • 从上面例子可以看出,map 生成的是个 1:1 映射,每个输入元素,都按照规则转换成为另外一个元素。还有一些场景,是一对多映射关系的,这时需要 flatMap。
  • flatMap 把 inpuStream 中的层级结构扁平化,就是将最底层元素抽出来放到一起,最终 output 的新 Stream 里面已经没有 List 了,都是直接的数字。

排序API测试

    @Test
public void sortTest() {
List<Integer> list = Arrays.asList(23, 45, -12, 2, 7, 89, 5);
System.out.println("----------从小到大排序测试---------");
list.stream().sorted().forEach(System.out::println);
System.out.println("----------从大到小排序测试---------");
list.stream().sorted((i1, i2) -> i2 - i1).forEach(System.out::println);
}

终止操作的部分API测试

    @Test
public void termOperationTest(){
List<Integer> list = Arrays.asList(23, 45, -12, 2, 7, 89, 5);
System.out.println("-----------allMatchTest-------------");
/**
* allMatch(Predicate predicate) -- 检查是否匹配所有元素
*/
boolean allMatch = list.stream().allMatch(integer -> integer > 0);
System.out.println(allMatch); System.out.println("-----------anyMatchTest-------------");
/**
* allMatch(Predicate predicate) -- 检查是否匹配所有元素
*/
boolean anyMatch = list.stream().anyMatch(integer -> integer > 0);
System.out.println(anyMatch); System.out.println("----------noneMatchTest-------------");
/**
* noneMatch(Predicate predicate) -- 检查是否没有匹配的元素
*/
boolean noneMatch = list.stream().noneMatch(integer -> integer > 0);
System.out.println(noneMatch); System.out.println("----------findFirstTest-------------");
/**
* findFirst() -- 返回流中第一个元素
*/
Optional<Integer> first = list.stream().findFirst();
System.out.println(first);
System.out.println("------------findAnyTest-------------");
/**
* findAny() -- 返回流中任一元素
*/
Optional<Integer> any = list.parallelStream().findAny();
System.out.println(any); System.out.println("--------------countTest-------------");
/**
* count() -- 返回流中元素的总个数
*/
long count = list.stream().filter(i -> i > 0).count();
System.out.println(count); System.out.println("------------max / min Test----------");
/**
* max/min(Comparator comparator) -- 返回流中最大值 / 最小值
*/
Optional<Integer> max = list.stream().max((i1, i2) -> i1 - i2);
System.out.println("max = " + max);
Optional<Integer> min = list.stream().min((i1, i2) -> i1 - i2);
System.out.println("min = " + min); System.out.println("--------------forEachTest------------");
/**
* forEach(Consumer c) -- 内部迭代
*/
// list.stream().forEach(System.out::println);
list.forEach(System.out::println);
}

规约操作部分API测试

    @Test
public void reduceTest(){
List<Integer> list = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
/**
* reduce(T identity, BinaryOperator) -- 可以将流中元素反复结合起来,得到一个值
*/
Integer reduce = list.stream().reduce(0, Integer::sum);
System.out.println("reduce = " + reduce); /**
* reduce(BinaryOperator) -- 可以将流中元素反复结合起来,得到一个值,返回optional
*/
Optional<Integer> reduce2 = list.stream().reduce(Integer::sum);
Optional<Integer> reduce3 = list.stream().reduce((i1, i2) -> i1 + i2);
System.out.println("reduce2 = " + reduce2);
System.out.println("reduce3 = " + reduce3);
}

collect部分API测试

@Test
public void collectTest(){
List<Integer> list = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
/**
*collect(Collector c) 将流转换为其他形式.接受一个Collector接口的实现
* 查找大于4的数字,结果返回一个list / set
*/
List<Integer> collectList = list.stream().filter(i -> i > 4).collect(Collectors.toList());
collectList.forEach(System.out::println);
Set<Integer> collectSet = list.stream().filter(i -> i > 4).collect(Collectors.toSet());
collectSet.forEach(System.out::println); }

Optional类

  • 到目前为止,臭名昭著的空指针异常是导致Java应用程序失败的最常见原因.

    以前,为了解决空指针异常,Google公司著名的Guava项目引入了Optional类,Guava通过使用检查空值的方式来防止代码污染,鼓励程序员写更干净的代码.受到Google Guava的启发,Optional类已经成为Java 8 类库的一部分

  • Optional类是一个容器类,他可以保存类型T的值,代表这个值存在,或者仅仅保存null,表示这个值不存在.原来用null表示一个值不存在,现在Optional可以更好地表达这个概念.并且可以避免空指针异常

  • Optional类的Javadoc描述如下: 这是一个可以为null的容器对象.如果值存在在isPresent()方法会返回true,调用get()方法会返回该对象

相关方法

# 1 创建Optional类对象的方法
- Optional.of(T t): 创建一个Optional实例,`t必须非空`
- Optional.empty(): 创建一个空的Optional实例
- Optional.ofNullable(T t): t可以为null # 2 判断Optional容器中是否包含对象:
- boolean isPresent(): 判断是否包含对象
- void ifPresent(Consumer consumer): 如果有值,就执行Consumer接口的实现代码,并且该值会作为参数传给它 # 3 获取Optional容器的对象
- T get(): 如果调用对象包含值,返回该值,否则抛异常
- T orElse(): 如果有值则将其返回,否则返回指定的other对象
- T orElseGet(Supplier other): 如果有值将其返回,否则返回由Supplier接口实现提供的对象
- T orElseThrow(Supplier exceptionSupplier): 如果有值则将其返回,否则抛出由Supplier接口实现提供的异常

相关方法代码测试

  • Girl实体类
public class Girl {
public Girl() {
} public Girl(String name) {
this.name = name;
} private String name; public String getName() {
return name;
} public void setName(String name) {
this.name = name;
}
}
  • Boy实体类
public class Boy {
private Girl girlFriend;
private String name; public Boy() {
} public Boy(Girl girlFriend, String name) {
this.girlFriend = girlFriend;
this.name = name;
} public Girl getGirlFriend() {
return girlFriend;
} public void setGirlFriend(Girl girlFriend) {
this.girlFriend = girlFriend;
} public String getName() {
return name;
} public void setName(String name) {
this.name = name;
}
}
    @Test
public void OptionalTest(){
Girl girl = new Girl();
girl=null;
Optional<Girl> optionalGirl = Optional.ofNullable(girl);
System.out.println("optionalGirl = " + optionalGirl);
} //原始的getName方法
public String getGirlName(Boy boy){
return boy.getGirlFriend().getName();
} //优化后的getName方法
public String getGirlNameAfterOptimizing(Boy boy){
Optional<Boy> boyOptional = Optional.ofNullable(boy);
//此时boy1一定非空
Boy boy1 = boyOptional.orElse(new Boy(new Girl("杨幂"), "我"));
Girl girlFriend = boy1.getGirlFriend();
Optional<Girl> girlFriend1 = Optional.ofNullable(girlFriend);
//girlOption一定非空
Girl girlOptional = girlFriend1.orElse(new Girl("赵丽颖")); return "女朋友的名字 : " + girlOptional.getName();
} @Test
public void testGetName(){
Boy boy = new Boy();
// boy = null;
boy.setGirlFriend(null);
// boy.setGirlFriend(new Girl("迪丽热巴"));
System.out.println(getGirlNameAfterOptimizing(boy));
}

Java中Stream流相关介绍的更多相关文章

  1. java中IO流相关知识点

    (一) 下边使用outputStream字节输出流进行写操作 package zdbIO;import java.io.File;import java.io.FileNotFoundExceptio ...

  2. java中数据流的简单介绍

    java中的I/O操作主要是基于数据流进行操作的,数据流表示了字符或者字节的流动序列. java.io是数据流操作的主要软件包 java.nio是对块传输进行的支持 数据流基本概念 “流是磁盘或其它外 ...

  3. 理解Java中字符流与字节流的区别

    1. 什么是流 Java中的流是对字节序列的抽象,我们可以想象有一个水管,只不过现在流动在水管中的不再是水,而是字节序列.和水流一样,Java中的流也具有一个“流动的方向”,通常可以从中读入一个字节序 ...

  4. 关于java中Stream理解

    关于java中Stream理解 Stream是什么 Stream:Java 8新增的接口,Stream可以认为是一个高级版本的Iterator.它代表着数据流,流中的数据元素的数量可以是有限的, 也可 ...

  5. 理解Java中字符流与字节流

    1. 什么是流 Java中的流是对字节序列的抽象,我们可以想象有一个水管,只不过现在流动在水管中的不再是水,而是字节序列.和水流一样,Java中的流也具有一个"流动的方向",通常可 ...

  6. 理解Java中字符流与字节流的区别(转)

    1. 什么是流 Java中的流是对字节序列的抽象,我们可以想象有一个水管,只不过现在流动在水管中的不再是水,而是字节序列.和水流一样,Java中的流也具有一个“流动的方向”,通常可以从中读入一个字节序 ...

  7. Java中的流(1)流简介

    简介 1.在java中stream代表一种数据流(源),java.io的底层数据元.(比作成水管)2.InputStream 比作进水管,水从里面流向你,你要接收,read3.OutputStream ...

  8. Java中Date各种相关用法

    Java中Date各种相关用法(一) 1.计算某一月份的最大天数 Java代码 Calendar time=Calendar.getInstance(); time.clear(); time.set ...

  9. Java中IO流的总结

    有关Java中IO流总结图 流分类 按方向分 输入流 输出流 按单位分 字节流 字符流 按功能分 节点流 处理流(过滤流) 其他 所有的流继承与这四类流:InputSteam.OutputStream ...

随机推荐

  1. 热更新基础--AssetBundle学习笔记

    一.简介 AssetBundle简称AB包,特定平台的资产压缩包(包括模型.贴图.预设体.音效.材质球等资产). 作用:Resources下的资源只读且打包后不可修改,而AB包存储位置自定,后期可以动 ...

  2. Java代码实现热部署

    一.思路 0. 监听java文件最后修改时间,如果发生变化,则表示文件已经修改,进行重新编译 1. 编译java文件为 class文件 2. 通过手写类加载器,加载 class文件 ,创建对象 3. ...

  3. Istio 生产环境用户流量接入方案

    总结Istio 生产环境用户流量接入方案 方案1 Client -> istioGateway域名(微服务) -> VritualService匹配路由并绑定网关 -> Destin ...

  4. Kafka 消息存储机制

    Kafka 消息以 Partition 作为存储单元,那么在 Partition 内消息是以什么样的格式存储的呢,如何处理 Partition 中的消息,又有哪些安全策略来保证消息不会丢失呢,这一篇我 ...

  5. 安卓安装kali linux之Termux

    解决安装kali无模组问题 https://blog.csdn.net/weixin_44690490/article/details/108599693?utm_source=app 步骤 1.获取 ...

  6. vue 快速入门 系列 —— vue 的基础应用(下)

    其他章节请看: vue 快速入门 系列 vue 的基础应用(下) 上篇聚焦于基础知识的介绍:本篇聚焦于基础知识的应用. 递归组件 组件是可以在它们自己的模板中调用自身的.不过它们只能通过 name 选 ...

  7. 网络编程之BIO和NIO

    目录 OSI网络七层模型 TCP/UDP协议 TCP消息头 TCP三次握手.四次挥手 UDP协议 TCP协议/UDP协议区别 HTTP协议 HTTP协议请求头 HTTP协议响应头 HTTP状态码 so ...

  8. 【Spring】SpringIoC大致流程

    目录 SpringIoC 是什么? 类图 大致过程 源码分析 SpringIoC 是什么? ​ 官方文档的解释是:IoC也称为依赖注入(DI).在此过程中,对象仅通过构造函数参数,工厂方法的参数或在构 ...

  9. 1438. Longest Continuous Subarray With Absolute Diff Less Than or Equal to Limit

    Given an array of integers nums and an integer limit, return the size of the longest continuous suba ...

  10. 功能:Java注解的介绍和反射使用

    功能:Java注解的介绍和反射使用 一.注解 1.注解介绍 java注解(Annotation),又称为java标注,是jdk5.0引入的一种机制. Java 语言中的类.方法.变量.参数和包等都可以 ...