Stream流
1 Stream流的概述
1.1 Stream流的目的
目的:用于简化集合和数组操作的API。
▶【案例】体现Stream流的作用
● 需求:按照下面的要求完成集合的创建和遍历
①创建一个集合,存储多个字符串元素
②把集合中所有以"张"开头的元素存储到一个新的集合
③把"张"开头的集合中的长度为3的元素存储到一个新的集合
④遍历上一步得到的集合中的元素输出。
public class StreamTest {
public static void main(String[] args) {
ArrayList<String> names = new ArrayList<>();
Collections.addAll(names,"张三丰","张无忌","周芷若","赵敏","张强");
System.out.println(names);
//1.从集合中找出姓张的放在新集合
ArrayList<String> zhangList = new ArrayList<>();
for (String name : names) {
if (name.startsWith("张")){
zhangList.add(name);
}
}
System.out.println(zhangList);
//2.找名称长度是3的名字
ArrayList<String> zhangThreeList = new ArrayList<>();
for (String name : zhangList) {
if (name.length()==3){
zhangThreeList.add(name);
}
}
System.out.println(zhangThreeList);
System.out.println("-------------------------------------------");
// 【使用Stream实现】
names.stream()
.filter(s -> s.startsWith("张"))
.filter(s -> s.length()==3)
.forEach(s -> System.out.println(s));
}
}
运行结果:
[张三丰, 张无忌, 周芷若, 赵敏, 张强]
[张三丰, 张无忌, 张强]
[张三丰, 张无忌]
-------------------------------------------
张三丰
张无忌
1.2 Stream流思想
① 先得到集合或者数组的Stream流(就是一根传送带)。
② 把元素放上去。
③ 然后就用这个Stream流简化的API来方便的操作元素。
2 Stream流的获取
2.1 Stream流的三类方法
● 获取Stream流 —— 创建一条流水线,并把数据放到流水线上准备进行操作
● 中间方法 —— 流水线上的操作,一次操作完毕后,还可以继续进行其它操作
● 终结方法 —— 一个Stream流只能由一个终结方法,是流水线上的最后一个操作
2.2 集合、数组获取流
● Stream操作集合/数组的第一步就是先得到Stream流,然后才能使用流的功能。
① 集合获取Stream流
可以使用Collection接口中的默认方法 stream() 来生成流
名称 | 说明 |
default Stream<E> stream() | 获取当前集合对象的stream流 |
② 数组获取Stream流
名称 | 说明 |
public static <T> Stream<T> stream(T[] array) | 获取当前数组的Stream流 |
public static<T> Stream<T> of(T... value) | 获取当前数组/可变数据的stream流 |
【案例】
public class StreamDemo02 {
public static void main(String[] args) {
/*-----------------Collection集合获取流-----------------*/
ArrayList<String> list = new ArrayList<>();
Stream<String> s = list.stream();
/*-----------------Map集合获取流-----------------*/
HashMap<String, Integer> maps = new HashMap<>();
//键流
Stream<String> keyStream = maps.keySet().stream();
//值流
Stream<Integer> valueStream = maps.values().stream();
//键值对流(拿整体)
Stream<Map.Entry<String, Integer>> keyAndValueStream = maps.entrySet().stream();
/*-----------------数组集合获取流-----------------*/
String[] names = {"赵敏","小昭","灭绝","周芷若"};
Stream<String> nameStream = Arrays.stream(names); //方式一
Stream<String> nameStream2 = Stream.of(names); // 方式二
}
}
3 Stream流的常用API
3.1 常用API(中间操作方法)
名称 | 说明 |
Stream<T> filter(Predicate<? super T> predicate) | 用于对流中的数据进行过滤 |
Stream<T> limit(long maxSize) | 获取前几个元素 |
Stream<T> skip(long n) | 跳过前几个元素 |
Stream<T> distinct() | 去除流中重复的元素。依赖(hashCode和equals方法) |
static <T> Stream<T> concat(Stream a, Stream b) | 合并a和b两个流为一个流 |
注意:
● 中间方法也称为非终结方法,调用完成后返回新的Stream流可以继续使用,支持链式编程。
● 在Stream流中无法直接修改集合、数组中的数据。
3.2 常见终结操作方法
名称 | 说明 |
void forEach(Consumer action) | 对此流的每个元素执行遍历操作 |
long count() | 返回此流中的元素数 |
注意:
● 终结操作方法,调用完成后流就无法继续使用了,原因是不会返回Stream了。
【案例】
/**
目标:Stream流的常用API
forEach : 逐一处理(遍历)
count:统计个数
-- long count();
filter : 过滤元素
-- Stream<T> filter(Predicate<? super T> predicate)
limit : 取前几个元素
skip : 跳过前几个
map : 加工方法
concat : 合并流。
*/
public class StreamDemo03 {
public static void main(String[] args) {
List<String> list = new ArrayList<>();
list.add("张无忌");
list.add("周芷若");
list.add("赵敏");
list.add("张强");
list.add("张三丰");
list.add("张三丰");
// Stream<T> filter(Predicate<? super T> predicate)
list.stream().filter(s -> s.startsWith("张")).forEach(s -> System.out.println(s));
long size = list.stream().filter(s -> s.length() == 3).count();
System.out.println(size);
// list.stream().filter(s -> s.startsWith("张")).limit(2).forEach(s -> System.out.println(s));
list.stream().filter(s -> s.startsWith("张")).limit(2).forEach(System.out::println);
list.stream().filter(s -> s.startsWith("张")).skip(2).forEach(System.out::println);
// map加工方法: 第一个参数原材料 -> 第二个参数是加工后的结果。
// 给集合元素的前面都加上一个:黑马的:
list.stream().map(s -> "黑马的:" + s).forEach(a -> System.out.println(a));
// 需求:把所有的名称 都加工成一个学生对象。
list.stream().map(s -> new Student(s)).forEach(s -> System.out.println(s));
// list.stream().map(Student::new).forEach(System.out::println); // 构造器引用 方法引用
// 合并流。
Stream<String> s1 = list.stream().filter(s -> s.startsWith("张"));
Stream<String> s2 = Stream.of("java1", "java2");
// public static <T> Stream<T> concat(Stream<? extends T> a, Stream<? extends T> b)
Stream<String> s3 = Stream.concat(s1 , s2);
s3.distinct().forEach(s -> System.out.println(s));
}
}
运行结果:
张无忌
张强
张三丰
张三丰
4
张无忌
张强
张三丰
张三丰
黑马的:张无忌
黑马的:周芷若
黑马的:赵敏
黑马的:张强
黑马的:张三丰
黑马的:张三丰
Student{name='张无忌'}
Student{name='周芷若'}
Student{name='赵敏'}
Student{name='张强'}
Student{name='张三丰'}
Student{name='张三丰'}
张无忌
张强
张三丰
java1
java2
4 收集Stream流
4.1 收集操作
● 收集Stream流的含义:就是把Stream流操作后的结果数据转回到集合或者数组中去。
● Stream流:方便操作集合/数组的手段。
● 集合/数组:才是开发中的目的。
4.2 收集方法
名称 | 说明 |
R collect(Collector collector) | 开始收集Stream流,指定收集器 |
Collectors工具类提供了具体的收集方式
名称 | 说明 |
public static <T> Collector toList() | 把元素收集到List集合中 |
public static <T> Collector toSet() | 把元素收集到Set集合中 |
public static Collector toMap(Function keyMapper , Function valueMapper) | 把元素收集到Map集合中 |
【案例】
/**
目标:收集Stream流的数据到 集合或者数组中去。
*/
public class StreamDemo05 {
public static void main(String[] args) {
List<String> list = new ArrayList<>();
list.add("张无忌");
list.add("周芷若");
list.add("赵敏");
list.add("张强");
list.add("张三丰");
list.add("张三丰");
Stream<String> s1 = list.stream().filter(s -> s.startsWith("张"));
List<String> zhangList = s1.collect(Collectors.toList()); // 可变集合
zhangList.add("java1");
System.out.println(zhangList);
// List<String> list1 = s1.toList(); // 得到不可变集合
// list1.add("java");
// System.out.println(list1);
// 注意注意注意:“流只能使用一次”
Stream<String> s2 = list.stream().filter(s -> s.startsWith("张"));
Set<String> zhangSet = s2.collect(Collectors.toSet());
System.out.println(zhangSet);
Stream<String> s3 = list.stream().filter(s -> s.startsWith("张"));
// Object[] arrs = s3.toArray();
String[] arrs = s3.toArray(String[]::new); // 可以不管,拓展一下思维!!
System.out.println("Arrays数组内容:" + Arrays.toString(arrs));
}
}
运行结果:
[张无忌, 张强, 张三丰, 张三丰, java1]
[张强, 张三丰, 张无忌]
Arrays数组内容:[张无忌, 张强, 张三丰, 张三丰]
注意:流只能用一次