什么是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. 8、MyBatis之使用注解开发

    9.使用注解开发 mybatis最初配置信息是基于 XML ,映射语句(SQL)也是定义在 XML 中的.而到MyBatis 3提供了新的基于注解的配置.不幸的是,Java 注解的的表达力和灵活性十分 ...

  2. 【vue开发】 计算属性传参

    <template> <div> {{test('zhende', 'np')}} </div> </template> <script> ...

  3. C语言之动态内存管理

    C语言之动态内存管理 大纲: 储存器原理 为什么存在动态内存的开辟 malloc() free() calloc() realloc() 常见错误 例题 柔性数组 零(上).存储器原理 之前我们提到了 ...

  4. Genymotion下载模拟器慢

    •问题来源 Genymotion 是个很不错的 Android 模拟器,系统更新快,启动速度快: 但是服务器在国外,Android 镜像下载起来那个速度就不敢恭维了: 当然如果你可以[科学,上网]就另 ...

  5. mysql基础自学

    1.1基础查询 语法:select 查询列表 from 表名;注意:1.查询列表可以是:表中的字段.常量值.表达式.函数2.查询的结果是一个虚拟表格 完整的写法是:先声明使用哪个库,再写SQL语 如果 ...

  6. Markdown部分用法总结

    1.Markdown数学公式&符号 2.Cmd Markdown 公式指导手册

  7. arthas使用

    博客原地址:https://blog.csdn.net/u013076044/article/details/83626202 arthas使用 文章目录 准备 启动Demo 进入arthas控制台 ...

  8. Python基础(十五):Python的3种字符串格式化,做个超全对比!

    有时候,为了更方便.灵活的运用字符串.在Python中,正好有3种方式,支持格式化字符串的输出 . 3种字符串格式化工具的简单介绍 python2.5版本之前,我们使用的是老式字符串格式化输出%s. ...

  9. Webpack的基本配置和打包与介绍(二)

    1. 前言 在上一章中我们学习到了webpack的基本安装配置和打包,我们这一章来学学如何使用loader和plugins 如果没看第一章的这里有传送门 2. Loader 2.1 什么是loader ...

  10. 击鼓传花联想到了Java设计模式:责任链模式

    目录 应用场景 简单示例 责任链模式 定义 意图 主要解决问题 何时使用 优缺点 击鼓传花的故事 应用场景 http web请求处理,请求过来后将经过转码.解析.参数封装.鉴权等一系列的处理(责任), ...