什么是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. 第1课:Linux操作系统基础【DevOps基础培训】

    第1课:Linux操作系统基础 --DevOps基础培训 1. 云主机.公网IP 1.1 公网ip和私网ip 只有公网ip是能够连接互联网的,私网IP 一般只用作局域网 我们能够上网靠的是isp组织分 ...

  2. kubernetes中有状态应用的优雅缩容

    将有状态的应用程序部署到Kubernetes是棘手的. StatefulSet使它变得容易得多,但是它们仍然不能解决所有问题.最大的挑战之一是如何缩小StatefulSet而不将数据留在断开连接的Pe ...

  3. 批量SSH key-gen无密码登陆认证脚本 附件脚本

    # 批量实现SSH无密码登陆认证脚本 ## 问题背景 使用为了让linux之间使用ssh不需要密码,可以采用了数字签名RSA或者DSA来完成.主要使用ssh-key-gen实现. 1.通过 ssh-k ...

  4. Vue 中的 mixin,component,render,hoc

    在项目中,一般我们经常会基于一套现有组件库进行快速开发,但是现实中往往需要对组件库进行定制化改造二次封装 混入(mixin) vue 官方介绍 混入 (mixin) 提供了一种非常灵活的方式,来分发 ...

  5. Dynamics CRM安装教程六:CRM产品安装

    接下来就要开始进行CRM产品的安装了 首先要安装IIS,以及.NET FrameWork4.6及相关功能 打开服务器管理器,在添加角色功能向导中勾选IIS,点击添加功能 默认下一步 选择角色服务这里的 ...

  6. python基础(补充):列表生成器

    列表推导式是Python构建列表(list)的一种快捷方式,可以使用简洁的代码就创建出一个列表. 举个例子,要生成list [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]可以用list ...

  7. 【深度学习】PyTorch CUDA环境配置及安装

    Pytorch版本介绍 torch:1.6 CUDA:10.2 cuDNN:8.1.0 安装 NVIDIA 显卡驱动程序 一般 电脑出厂/装完系统 会自动安装显卡驱动 如果有 可直接进行下一步 下载链 ...

  8. Day14_84_通过反射机制修改和获取class里的属性值

    通过反射机制修改和获取class里的属性值 * 属性对象.set(Object,属性值) 给Object对象中的某个属性赋值(属性对象) * 属性对象.get(Object); 获取Object对象中 ...

  9. Kubernetes 降本增效标准指南 | 基于K8s 扩展机制构建云上成本控制系统

    作者 王玉君,腾讯云后台高级开发工程师,负责腾讯云原生系统开发及建设. 晏子怡,腾讯云容器产品经理,在K8s弹性伸缩.资源管理领域有丰富的实战经验. 导语 Kubernetes 作为 IaaS 和 P ...

  10. k8s daemonset

    DaemonSet控制器会在每个节点上运行单一的副本,他非常适合部署那些节点本身提供服务或者执行维护的 Pod 例如 : 存储相关,每个节点上运行glusterd, ceph 日志收集相关,每个节点上 ...