Java—Stream流
目录
初识Stream流
Stream流的使用步骤
获取Stream流
单列集合获取Stream流
双列集合获取Stream流
数组获取Stream流
零散数据获取Stream流
Stream流的中间方法
filter
limit、skip
distinct
concat
map
Stream流的终结方法
toArray
collect
初识Stream流
在Java中,Stream流是一种用于处理集合类(如List、Set和Map)中元素的工具。Stream API 引入于 Java 8,它允许我们以声明式的方式进行数据操作。使用 Stream API 可以使代码更简洁、更易读,同时利用并行处理来提升性能。
Stream流的使用步骤
Stream流的使用步骤如下
1. 先获取一条Stream流(流水线),并把数据放上去;
2. 使用中间方法对流水线上的数据进行操作;
3. 使用终结方法对流水线上的数据进行操作。
获取Stream流
如下表所示不同数据类型获取Stream流的方式各不相同。
单列集合获取Stream流
ArrayList<String> list = new ArrayList<>();
Collections.addAll(list, "a", "b", "c", "d", "e");
// 获取流水线,并打印元素
list.stream().forEach(e -> System.out.printf(e));//abcde
双列集合获取Stream流
双列集合可以通过两种方式获取Stream流
1. 通过hm.keySet().stream()获取集合中所有的键的stream流;
2. 通过hm.entrySet().stream()获取集合中所有键值对的stream流。、
代码示例
HashMap<String, Integer> hm = new HashMap<>();
hm.put("aaa", 111);
hm.put("bbb", 222);
hm.put("ccc", 333);
hm.put("ddd", 444);//第1种获取stream流的方法:获取集合中的所有键
hm.keySet().stream().forEach(e-> System.out.println(e));
/*
aaa
ccc
bbb
ddd
*///第2种获取stream的流方法:获取集合中的所有键值对
hm.entrySet().stream().forEach(e-> System.out.println(e));
/*
aaa=111
ccc=333
bbb=222
ddd=444
*/
数组获取Stream流
数组可以通过两种方式获取Stream流
1. 通过Arrays.stream(arr)方法获取Stream流;
2. 通过Stream.of(arr)方法获取Stream流,因为该方法的形参是不可变参数,因此可以传入数组类型。但弊端在于,传入数组必须是引用数据类型的,如果传递基本数据类型,是会把整个数组当做一个元素,放到Stream流当中,因此并不建议使用该方法获取数组的Stream流。
示例代码
int[] arr = {1, 2, 3};
String[] strings = {"a", "b", "c"};// 1.通过Arrays.stream()获取stream流
Arrays.stream(arr).forEach(e -> System.out.println(e));
/*
1
2
3
*/// 2.通过Stream.of()获取stream流(不建议使用)
Stream.of(arr).forEach(e-> System.out.println(e)); //[I@3b9a45b3
Stream.of(strings).forEach(e -> System.out.println(e));
/*
a
b
c
*/
零散数据获取Stream流
零散数据可以通过Stream.of()的方式获取stream流,但是需要保证传入的数据类型都是相同的。
Stream.of("a", "b", "c").forEach(e -> System.out.println(e));
/*
a
b
c
*/Stream.of(1,2,3).forEach(e-> System.out.println(e));
/*
1
2
3
*/
Stream流的中间方法
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<R> map(Function<T ,R> mapper) // 转换流中的数据类型
注意1:中间方法,返回新的Stream流,原来的Stream流只能使用一次,建议使用链式编程
注意2:修改Stream流中的数据,不会影响原来集合或者数组中的数据
filter
ArrayList<String> list = new ArrayList<>();
Collections.addAll(list, "张无忌", "周芷若", "张三", "张三丰", "赵敏", "张良", "李四");//filter:过滤 需求:留下以张开头的字符串
list.stream().filter(new Predicate<String>() {@Overridepublic boolean test(String s) {//如果返回值为true,表示留下当前数据//如果返回值为false,表示舍弃当前数据return s.startsWith("张");}
}).forEach(e -> System.out.println(e));//链式编程:留下以张开头且长度为3的字符串
list.stream().filter(s -> s.startsWith("张")).filter(s -> s.length() == 3).forEach(e -> System.out.println(e));Stream<String> stream1 = list.stream();
Stream<String> stream2 = stream1.filter(s -> s.startsWith("张"));
Stream<String> stream3 = stream1.filter(s -> s.length() == 3);//报错:stream1已经被使用过一次,不可再次被使用
limit、skip
ArrayList<String> list = new ArrayList<>();
Collections.addAll(list, "张无忌", "周芷若", "张三", "张三丰", "赵敏", "张良", "李四");//获取前3个数据
list.stream().limit(3).forEach(e-> System.out.printf(e+" "));//张无忌 周芷若 张三
//跳过前4个数据
list.stream().skip(4).forEach(e-> System.out.printf(e+" "));//赵敏 张良 李四
distinct
注意:distinct底层依赖hashCode和equals两个方法对集合中的元素进行去重,如果集合中的元素类型是自定义类,则需要重写这两个方法。
ArrayList<String> list = new ArrayList<>();
Collections.addAll(list, "张三", "张三", "张三", "张三", "赵敏", "张良", "李四");list.stream().distinct().forEach(e-> System.out.printf(e+" "));//张三 赵敏 张良 李四
concat
ArrayList<String> list1 = new ArrayList<>();
Collections.addAll(list1, "张三", "张三");
ArrayList<String> list2 = new ArrayList<>();
Collections.addAll(list2, "李四", "李四");Stream.concat(list1.stream(),list2.stream()).forEach(e-> System.out.printf(e+" ")); //张三 张三 李四 李四
map
ArrayList<String> list = new ArrayList<>();
Collections.addAll(list, "张无忌-12", "赵敏-22", "张良-8", "李四-26");//需求:获取字符串的数字部分
//Function<E, T>,E代表元素原来的类型,T代表元素转换后的类型
//需要保证apply返回值类型与T相同
list.stream().map(new Function<String, Integer>() {@Overridepublic Integer apply(String s) {//将字符串进行分割String[] arr = s.split("-");//取出字符串的年龄部分String ageString = arr[1];int age = Integer.parseInt(ageString);return age;}
}).forEach(e-> System.out.println(e));//Lambda简化
list.stream().map(s->Integer.parseInt(s.split("-")[1])).forEach(e-> System.out.println(e));
Stream流的终结方法
void forEach(Consumer action) //遍历
long count() //统计
toArray() //收集流中的数据,放到数组中
collect(Collector collector) //收集流中的数据,放到集合中(List,Set,Map)
toArray
ArrayList<String> list = new ArrayList<>();
Collections.addAll(list, "张无忌", "赵敏", "张良", "周芷若");//转换成Object类型的数组
Object[] objects = list.stream().toArray();//转换成指定类型的数组
String[] strings1 = list.stream().toArray(new IntFunction<String[]>() {@Override//value表示的是stream流中元素的个数public String[] apply(int value) {return new String[value];}
});//Lambda简化
String[] strings2 = list.stream().toArray(value -> new String[value]);
collect
通过collect方法将Stream流转换为List、Set集合,代码如下
ArrayList<String> list = new ArrayList<>();
Collections.addAll(list, "张无忌-男-12", "张无忌-男-12", "赵敏-女-19", "张三丰-男-25", "周芷若-女-22", "张良-男-28", "谢广坤-男-30");//将性别为"男"的元素搜集到List集合中,元素不去重
List<String> newList = list.stream().filter(s -> "男".equals(s.split("-")[1])).collect(Collectors.toList());//将性别为"男"的元素搜集到Set集合中,元素去重
Set<String> newSet = list.stream().filter(s -> "男".equals(s.split("-")[1])).collect(Collectors.toSet());
通过collect方法将Stream流转换为Map集合,注意需要保证键的唯一性,代码如下
ArrayList<String> list = new ArrayList<>();
Collections.addAll(list, "张无忌-男-12", "赵敏-女-19", "张三丰-男-25", "周芷若-女-22", "张良-男-28", "谢广坤-男-30");//将性别为"男"的元素搜集到Set集合中,规定键为姓名,值为年龄
Map<String, Integer> collect = list.stream().filter(s -> "男".equals(s.split("-")[1]))/*** toMap: 参数1表示键的生成规则* 参数2表示值的生成规则** 参数1:* Function<流中每一个数据的类型,Map集合中键的数据类型>(){* public Map集合中键的数据类型 apply(流中每一个数据的类型 s){* 生成键的代码* 返回键;* }* }***参数2:* Function<流中每一个数据的类型,Map集合中值的数据类型>(){* public Map集合中值的数据类型 apply(流中每一个数据的类型 s){* 生成值的代码* 返回值;* }* }** */.collect(Collectors.toMap(new Function<String, String>() {@Overridepublic String apply(String s) {return s.split("-")[0];}},new Function<String, Integer>() {@Overridepublic Integer apply(String s) {return Integer.valueOf(s.split("-")[2]);}}));//Lambda表达式简化
Map<String, Integer> collect1 = list.stream().collect(Collectors.toMap(s -> s.split("-")[0], s -> Integer.valueOf(s.split("-")[2])));