转自公众号:后端技术精选

此处的流(Stream)与io中的输入流(InputStream)与输出流(OutputStream)是不同的概念,与实时处理数据的流也是不同的概念,但它们也有相似之处。

Stream是对集合类的增强,它将List、Map等集合作为数据源,串行或并行地操作集合类,这些操作包括遍历(foreach)、过滤(filter)、排序(sort)、匹配(match)、映射(map)、计数(count)等,上述操作分为两种类型:

1、中间操作:该操作将会计算数据,返回计算后的流
2、终端操作:该操作会关闭流,返回最终数据

为了进行运算,Stream操作被放入到流管道中,流管道由数据源(可以是数组、集合、I/O通道等)、转换流的中间操作(比如filter)、返回数据结果的最终操作组成(比如count和foreach)。

流管道示意图:

Java中流特性:

  • 不是数据结构

  • 并不储存数据,所有的操作从源抓取

  • 不会影响源数据

  • 不支持索引访问(但可以使用IntStream曲线救国)

  • 惰性

    • 只有最终操作被启动时,才会计算源数据

    • 只有当需要的时候才使用源元素(提供源数据的元素)

  • 并行

BaseStream

所有的流都继承此接口

java
// 继承自AutoCloseable,说明流都是自动关闭的
public interface BaseStream<T, S extends BaseStream<T, S>>extends AutoCloseable {// 下面是所有流都拥有的方法// 返回当前流元素的迭代器(终端操作)Iterator<T> iterator();// 返回当前流元素的可切割迭代器(终端操作)Spliterator<T> spliterator();// 是否并行流boolean isParallel();// 返回当前流的串行流,若当前流已经是串行或流已经被修改为串行,返回自己S sequential();// 返回当前流的并行流,若当前流已经是并行或流已经被修改为并行,返回自己S parallel();// 返回当前流的乱序流,若当前流已经是乱序或流已经被修改为乱序,返回自己S unordered();// 返回添加了额外的流关闭处理器的流,当close()方法执行的时候调用。// 所有的流关闭处理器都会被执行,即使某处理器发生异常,S onClose(Runnable closeHandler);void close();
}

Java基于BaseStream提供了众多数据流的封装,其中基于原始数据类型的数据流封装较为常用,比如:IntStream、DoubleStream、LongStream、

Stream

继承自BaseStream

Stream API如下图:

生成流的几种方式

1、数组方式

java
// 1.
Stream aryStream = Stream.of(ary);
// 2.
Arrays.stream(ary);

2、集合方式

java
// 串行
List<String> list = new ArrayList<>();
list.add("1");
list.add("1");
list.add("1");
Stream stream = list.stream();
// 并行
List<String> list2 = new ArrayList<>();
list2.add("1");
list2.add("1");
list2.add("1");
Stream stream = list.parallelStream();

3、静态工厂

java
// 这种方式可以解决下标问题
int[] ary = {1,2,3,4,5,6,7,8,9};
IntStream.range(0,ary.length).forEach(System.out::println);//   不包含10
IntStream.rangeClosed(0,ary.length).forEach(System.out::println);// 包含10

4、I/O

java
BufferedReader bufferedReader = new BufferedReader(new FileReader("project.properties"));
Stream<String> stream = bufferedReader.lines();

5、其他

java
// 1.
Random random = new Random();
IntStream stream1 = random.ints();
// 2.
Path path = Paths.get("D:\\记事本.txt");
Stream<String> lines = Files.lines(path, StandardCharsets.UTF_8);

常用操作示例

下文示例中使用到的Widget实体及集合

java
class Widget{private String color;private int weight;// ...省略g&t
}
private Widget w1 = new Widget("RED",20);
private Widget w2 = new Widget("GREEN",20);
private Widget w3 = new Widget("GRAY",20);
private List<Widget> widgetList = new ArrayList<>();
{widgetList.add(w1);widgetList.add(w2);widgetList.add(w3);
}

filter

java
@Test
public void stream(){// 统计红色小组件个数System.out.println(widgetList.stream().filter(w -> w.getColor().equals("RED")).count());// 统计红色小组件总重System.out.println(widgetList.stream().filter(w -> w.getColor().equals("RED"))//  w -> w.getWeight()//  method reference 使用 Widget::getWeight 替代 w -> w.getWeight//  方法引用可以用来替换λ表达式.mapToInt(Widget::getWeight).sum());
}

filter的入参是谓词 Predicate ,如果一个操作使用频繁,我们可以先写好一个 Predicate ,之后使用它就可以了

java
/*谓词,filter方法接收的编程式函数(functional interface)*/
private static Predicate<Widget> isRedWidget(){return widget -> widget.getColor().equals("RED");
}/*filter forEach forEachRemaining*/
@Test
public void stream(){//  predicateList<Widget> newWidgets = widgetList.stream().filter(isRedWidget()).collect(Collectors.toList());newWidgets.forEach(System.out::println);newWidgets.iterator().forEachRemaining(System.out::println);
}
//  输出
com.baosight.test.StreamTest$Widget@26f67b76
com.baosight.test.StreamTest$Widget@26f67b76

map

java
@Test
public void map(){String[] ary = {"Hello","world","John sena"};// peek不是最终操作,所以下面这条语句不会输出任何东西// 这就验证了前面提到的Streams are lazyArrays.stream(ary).map(String::toUpperCase).peek(word -> System.out.println("Mapped value:"+word));Arrays.stream(ary).map(String::toUpperCase).peek(word -> System.out.println("Mapped value:"+word)).count();
}
//  输出
Mapped value:HELLO
Mapped value:WORLD
Mapped value:JOHN SENA

collect

java
@Test
public void stream(){List<Integer> list = Stream.of(1, 2, 3, 45, 6, 7, 8, 5, 435).collect(Collectors.toList());System.out.println(list.toString());String string = Stream.of("1","2").collect(Collectors.joining(","));System.out.println(string);Map widgetMap = widgetList.stream().collect(Collectors.groupingBy(Widget::getColor));//  收集行为可以级联Map widgetMap2 = widgetList.stream().collect(Collectors.groupingBy(Widget::getColor,Collectors.groupingBy(Widget::getWeight)));System.out.println(widgetMap.toString());
}
//  输出
[1, 2, 3, 45, 6, 7, 8, 5, 435]
1,2
{RED=[com.baosight.test.StreamTest$Widget@61a485d2], GRAY=[com.baosight.test.StreamTest$Widget@39fb3ab6], GREEN=[com.baosight.test.StreamTest$Widget@6276ae34]}

reduce

java
/*Instant LongStream.rangeClosed*/
@Test
public void stream(){//  instant类用于获取时间线上的时间点Instant start = Instant.now();// 计算范围内的和long r = LongStream.rangeClosed(0, 100000).parallel()// 并行流// .sequential() 串行流.reduce(0, Long::sum);Instant end = Instant.now();//  迭代器 forEach和forEachRemaining 的区别://  forEach可以多次调用,对元素多次处理//  forEachRemaining对所有元素只处理一次//  所以在第二次调用同一个迭代器的forEachRemaining方法时无作为Iterator iterator = newWidgets.iterator();iterator.forEachRemaining(System.out::println);iterator.forEachRemaining(System.out::println);
}
// 输出
5000050000
本次执行耗时:62

sort

java
/*sorted*/
@Test
public void stream(){//  排序Integer i[] = {1,2,3,5,6,7,9,45,9,324,22};List<Integer> integers = Arrays.asList(i);integers.stream().sorted().forEach(System.out::println);
}
//  输出
1
2
3
5
6
7
9
9
22
45
324

distinct

java
/*distinct*/
@Test
public void stream(){//  去重Integer i[] = {1,2,2,2,27,2,2,9,324,22};List<Integer> integers = Arrays.asList(i);integers.stream().distinct().forEach(System.out::println);
}
//  输出
1
2
27
9
324
22

下标

java
@Test
/*IntStream.range/rangeClosed*/
public void stream(){int[] ary = {1,2,3,4,5,6,7,8,9};
//    Stream aryStream = Stream.of(ary);
//    Arrays.stream(ary);//IntStream 可以用来当作遍历的下标IntStream.range(0,ary.length).forEach(System.out::println);//   不包含10IntStream.rangeClosed(0,ary.length).forEach(System.out::println);// 包含10IntStream.range(0,ary.length).forEach( i -> System.out.println(i*666));
}

flatMap

java
class Order{private String orderNo;private String orderName;private List<OrderLineItem> lineItems;//...省略g&t
}
class OrderLineItem{private String lineNo;private String lineName;//...省略g&t
}
@Test
/*produce a new stream*/
public void stream(){List<Order> orders = new ArrayList<>();List<OrderLineItem> lineItems = new ArrayList<>();lineItems.add(new OrderLineItem("1", "one"));lineItems.add(new OrderLineItem("2", "two"));lineItems.add(new OrderLineItem("1", "three"));lineItems.add(new OrderLineItem("1", "four"));lineItems.add(new OrderLineItem("1", "five"));orders.add(new Order("1","one",lineItems));orders.add(new Order("2", "two", lineItems));orders.add(new Order("3", "three", lineItems));// orders的流中将所有orders的lineItems组装起来返回一个新的流,// 这个流中有所有order的所有orderLineItem(在当前测试方法中有15个,3*5)List data = orders.stream().flatMap(order -> order.getLineItems().stream()).collect(Collectors.toList());System.out.println(data.size());
}
//  输出
15

peek

java
/*peek*/
@Test
public void stream(){//  就像名字一样,窥视 233List<String> list = Stream.of("one","two","three","four","five").filter(e -> e.length() > 3).peek(e -> System.out.println("Filtered value:"+e)).map(String::toUpperCase).peek(e -> System.out.println("Maped value:"+e)).collect(Collectors.toList());
}
//  输出
Filtered value:three
Maped value:THREE
Filtered value:four
Maped value:FOUR
Filtered value:five
Maped value:FIVE

anyMatch/allMatch/noneMatch

java
@Test
public void match() {//  匹配boolean match = widgetList.stream().anyMatch(isRedWidget());boolean match2 = widgetList.stream().allMatch(isRedWidget());boolean match3 = widgetList.stream().noneMatch(isRedWidget());System.out.println(match);System.out.println(match2);System.out.println(match3);
}
//  输出
true
false
false

limit、skip

java
/*limit skip*/
@Test
public void stream(){//  两个作用类似,一个限制n个元素,一个跳过n个元素List<Integer> list = Stream.of(1, 2, 3, 45, 6, 7, 8, 5, 435).limit(5).collect(Collectors.toList());System.out.println(list.toString());List<Integer> list2 = Stream.of(1, 2, 3, 45, 6, 7, 8, 5, 435).skip(5).collect(Collectors.toList());System.out.println(list.toString());
}
//  输出
[1, 2, 3, 45, 6]
[1, 2, 3, 45, 6]

min、max

java
@Test
public void minAndMax() {Comparator comparator = (o1, o2) -> (int) o1 > (int) o2 ? 1 : -1;Optional optional = Stream.of(1, 2, 3, 45, 6, 7, 8, 5, 435).min(comparator);System.out.println(optional.get());Optional optional2 = Stream.of(1, 2, 3, 45, 6, 7, 8, 5, 435).max(comparator);System.out.println(optional2.get());
}
// 输出
1
435

findFirst/findAny

java
@Test
public void find() {//  findFirst返回流中第一个元素//  findAny返回流中任意元素Optional optional = widgetList.stream().findFirst();Optional optional2 = widgetList.stream().findAny();Widget widget = (Widget) optional.get();Widget widget2 = (Widget) optional2.get();System.out.println(widget.getColor());System.out.println(widget2.getColor());
}

toArray

java
/*toArray*/
@Test
public void steam(){Widget[] widgets = widgetList.stream().filter(widget -> widget.getColor().equals("RED")).toArray(Widget[]::new);
}

Java流及流操作示例相关推荐

  1. java 合并流_Java Stream 流实现合并操作示例

    本文实例讲述了Java Stream 流实现合并操作.分享给大家供大家参考,具体如下: 1. 前言 Java Stream Api提供了很多有用的 Api 让我们很方便将集合或者多个同类型的元素转换为 ...

  2. java 创建gbase_GBase8s + MyBatis 操作示例

    GBase8s Spring Boot MyBatis 操作示例 本文将创建一个简单的 Spring Boot 项目结构,并演示如何使用 Mybatis 进行GBase 8s 数据库的数据 处理工作( ...

  3. Java Streams:流操作及示例

    正如我们在Java Streams:流创建中所学到的,流管道由源.零个或多个中间操作和一个终端操作组成. 我们还了解到,streams流是懒惰的:仅当终端操作启动时,才对源数据执行计算. 在本文中,我 ...

  4. java crud_Java 8流中的数据库CRUD操作

    java crud 在开始使用新工具时要克服的最大障碍是让您着手处理小事情. 到目前为止,您可能对新的Java 8 Stream API的工作方式充满信心,但是您可能尚未将其用于数据库查询. 为了帮助 ...

  5. Java中的流(概念和示例)

    首先,流是什么? 流是个抽象的概念,是对输入输出设备的抽象,Java程序中,对于数据的输入/输出操作都是以"流"的方式进行.设备可以是文件,网络,内存等. 流具有方向性,至于是输入 ...

  6. Java 8 Stream流的常见操作

    Stream流的使用 在 Java 8 中, 集合接口有两个方法来生成流: stream() − 为集合创建串行流.parallelStream() − 为集合创建并行流. 串行流 如果是数组的话,可 ...

  7. 黑马毕向东Java课程笔记(day19-11——19-22)IO字节流:字节流及其读取、字节流缓冲区、自定义字节流(读取)的缓冲区、读取键盘的输入、读取/写入转换流、流操作规律

    1.字节流--File   字节流的介绍 字符流:(一个字符2个字节16位) FileReader FileWriter. BufferedReader BufferedWriter字节流:(一个字节 ...

  8. Java基础IO流概述、字符流、字节流、流操作规律、File类、Properties类、打印流、序列流

    IO流:(Input Output)流 字符流的由来:其实就是字节流读取文字字节数据后,不直接操作而是先查指定的码表,获取对应的文字进行操作 简单说:字符流 = 字节流 + 编码表 字节流的两个顶层父 ...

  9. Java 8 - Stream流骚操作解读2_归约操作

    文章目录 Pre 什么是归约操作 元素求和 reduce reduce如何运行的 最大值和最小值 Pre Java 8 - Stream流骚操作解读见到过的终端操作都是返回一个 boolean ( a ...

最新文章

  1. 【图像分类案例】(2) DenseNet 天气图片四分类(权重迁移学习),附Tensorflow完整代码
  2. 深入理解 RPC 之集群篇
  3. Android面试收集录13 Android虚拟机及编译过程
  4. C#中File的使用
  5. abstract和interface
  6. 如何打通“鱼塘” ?腾讯启动“SaaS技术联盟” 共建技术中台
  7. 什么样的程序员是最让人讨厌的?朋友们注意了,别做这种人!
  8. (TI xDM)SSCR Module—Shared Scratch Memory
  9. 新一代华为折叠屏手机MateX2,你会考虑入手吗?
  10. Android的ListFragment和Fragment的使用
  11. python 特殊字符作为分割行 调整非时间开头格式
  12. parentNode,parentElement,offsetParent
  13. Android初学第9天
  14. 前端技术栈---Vue(1)安装与初始化
  15. 计算机第二章测试题及答案,计算机组成原理第二章练习题及答案
  16. sqlserver 企业版下载地址
  17. PHP开发小技巧①②—一些常用的PHP正则表达式
  18. php px与rem转换,pt 与 px、em、rem 的区别与换算
  19. Python - PyMuPDF (fitz) 处理 PDF
  20. 微信小程序中苹果iOS手机显示时间格式NaN不正确的问题

热门文章

  1. 游戏建模的工具主要有哪些?
  2. HMC5883L 电子指南针
  3. 波特率dlm_第6讲 串行通信16550.ppt
  4. 分形图的递归算法简介
  5. html查看蛋白质,怎么查询蛋白质的全部信息-- UniProKB数据库
  6. QT xml转ini的实现(从C#转到QT)
  7. BF(暴力)算法详解
  8. Font Awesome 的使用
  9. 虹科教您|实现OPC UA C/S快速部署及数据采集
  10. 路由、路由器、路由表介绍