Java 8中新特性Stream的基本理解和使用
Stream基本概念
Stream流是来自数据源的元素队列并支持聚合操作
**元素:**是特定类型的对象,是数据源形成的一个队列。Java中Stream不会存储元素,而是按需计算
数据源:Stream流数据的来源。可以是集合,数组,I/O Channel ,产生器Generator等
聚合操作:类似SQL语句的一系列操作,比如filter,map,sorted等。
Stream不是集合元素,不是数据结构来保存数据,是一个有关数据算法和计算的流:
获取一个数据源source => 数据转换 => 执行操作获取需要的结果,每次转换后原来的Stream对象不变,返回一个新的Stream对象,这样可以使得对Stream的操作链式排列,形成一个管道
还是不能理解?
简洁理解
Stream是对集合Collection对象功能的增强,Stream可以对集合对象进行便利高效的聚合操作和大批量的数据操作,集合类存有的元素都是划分内存空间存储的,数据量很大的集合类会占用大量的内存。Stream的元素是延迟计算的,即只有在访问的时候才会进入内存进行计算。
其次集合类的迭代逻辑是调用者负责的,通常使用for循环。Stream中的迭代是隐含在对Stream的各种操作当中的。
Stream操作的基本特征:
****Pipelining:****中间操作都会返回流本身。多个操作可以串成一个管道。这样就可以对操作进行优化,比如延迟执行和短路
内部迭代:对集合的遍历都是Iterator或者是for-Each操作,显示地在集合外部进行迭代。Stream提供了内部迭代的方式,通过访问者模式Vistor实现
Stream的特点:
不存储:
数据流Stream不是存储元素的数据结构
数据流Stream将数据元素从源数据 结构,数组,生成器函数和输入输出管道中传递到计算机操作的管道中
功能性:
一个数据流Stream中的流操作都会产生一个结果,不会修改源数据Stream中的元素
延迟计算
许多流操作中的各种操作,比如过滤,映射,去重等,只有访问时才会进行计算,这样可以有更多的机会进行优化
无界性
集合的大小是有界的,但数据流Stream可以是无界的,短路操作等可以允许无限流计算在有限的时间内完成。
如何生成流 ?
集合接口有两种方式生成流:
stream():为集合创建串行流
paralleStream():为集合创建并行流,并行流可以充分发挥多核处理器的优势,使用fork和join并行方式来拆分任务和加速处理过程
stream()
创建第一个示例:
实际运用:如项目中查找学生成绩为空的学生信息
****注意:****Arrays.asList()是一个Java数组与集合之间的桥梁方法,它可以将一个数组转换为一个List集合。使用Arrays.asList()方法,我们可以将一个数组转换为一个List集合,然后使用List的方法来操作这个集合
//输出不是空的字符串
List<String> strings= Arrays.asList("abs","","dda","","dark","");
List<String> filtered = strings.stream().filter(string -> !string.isEmpty()).collect(Collectors.toList());
System.out.println(filtered);
运行结果:
forEach和limit
提供更好的遍历方式,遍历数据
Stream 提供新的方法 ’ forEach‘ 来迭代流中的每个数据。
limit方法用于获取指定数量的流
通过流方式随机打印10条数据
//使用forEach输出10个随机数
Random random = new Random();
random.ints().limit(15).forEach(System.out::println);
运行结果:
map
map方法用于映射每个元素到对应的结果
//使用map输出元素的2的倍数
List<Integer> numbers = Arrays.asList(155,151,4,56,2,3,15,30);
List<Integer> dList = numbers.stream().map(x -> 2*x).collect(Collectors.toList());
System.out.println(dList);
运行结果:
filter
filter 方法用于通过设置的条件过滤出元素
//使用filter方法过滤出空字符串
List<String> strings1 = Arrays.asList();
//获取空字符串的数量
long count = strings1.stream().filter(string -> string.isEmpty()).count();
System.out.println(count);
sorted
sorted方法用于对流进行排序
对随机生成的数进行排序:
//使用forEach输出10个随机数
//ints()返回的是整数值最大到最小(即Long范围内)
Random random = new Random();
random.ints().limit(10).sorted().forEach(System.out::println);
运行结果:
Collectors(收集器)
Collectors类实现了很多规约操作(即将数据流收集成另外一种数据格式,如:toList、toSet、toMap等数据结构),将流数据转换为集合或者聚合集合。之前字符串拼接一般是用StringBuffer的append()方法。在JDK8中,可以采用函数式编程(使用Collectors.join 收集器)的方式对字符串进行更优雅的拼接。Collectors.joining收集器:支持灵活的参数配置,可以指定字符串连接时的分隔符,前缀和后缀字符串
示例1:
//定义一个String类型的集合
List<String> strings2 = Arrays.asList("abs","","dda","","dark","");
//将strings2字符串集合按照非空的条件过滤筛选出来到一个新集合内
List<String> filtered1 = strings2.stream().filter(string -> !string.isEmpty()).collect(Collectors.toList());
System.out.println("筛选后的字符串集合:"+filtered1);
//将filtered1集合通过Collectors聚合为一个字符串,按“”的方式连接
String mergedString = strings2.stream().filter(string -> !string.isEmpty()).collect(Collectors.joining());
System.out.println("合拼的字符串"+mergedString);
运行结果:没有任何分隔符的将字符串合拼在一起
示例2:
String mergedString = strings2.stream().filter(string -> !string.isEmpty()).collect(Collectors.joining("->"));
运行结果:通过"->"分隔符将字符串拼接
示例3:
String mergedString1 = strings2.stream().filter(string -> !string.isEmpty()).collect(Collectors.joining("-》","{","}"));
System.out.println("合拼的字符串2:"+mergedString1);
运行结果:通过"-》"分隔拼接的同时同时设置前缀和后缀
统计
另外,一些产生统计结果的收集器也很有用
如:开发时会对价格进行求平均,总和,找到最大或者最小值时就能便捷的使用
示例:
SqlSession sqlSession = sqlSessionUtil.getSqlSession();
//获取StudentDao对象
StudentDao studentDao = sqlSession.getMapper(StudentDao.class);
//获取所有学生对象信息
List<Student> list = studentDao.getAllStudents();
list.forEach(System.out::println);
IntSummaryStatistics summaryStatistics = list.stream().mapToInt(student -> student.getSage()).summaryStatistics();
System.out.println("他们的年龄和为:" + summaryStatistics.getSum());
System.out.println("他们的平均年龄为:"+summaryStatistics.getAverage());
System.out.println("他们之间最大年龄为:"+summaryStatistics.getMax());
System.out.println("他们之间最小年龄为:"+summaryStatistics.getMin());
System.out.println("数据库中总的数据条数为:"+summaryStatistics.getCount());
运行结果:
parallelStream
parallelStream是流并行处理程序的代替方法,可以和stream()的顺序运行之间任意切换
//使用filter方法过滤出空字符串
List<String> strings1 = Arrays.asList("abs","","dda","","dark","");
//获取空字符串的数量
long count = strings1.parallelStream().filter(string -> string.isEmpty()).count();
System.out.println(count);
运行结果: