什么是Stream?
Stream
将要处理的元素集合看作一种流,在流的过程中,借助Stream API
对流中的元素进行操作,比如:筛选、排序、聚合等
Stream流的作用:
结合了Lambda表达式,简化集合、数组的操作
Stream流的使用步骤:
①先得到一条Stream流(流水线),并把数据放上去
②利用Stream流中的API进行各种操作:比如
中间方法:(过滤、转换) 方法调用完毕之后,还可以调用其他方法
终结方法:(统计、打印) 最后一步,调用完毕之后,不能调用其它方法
总的来说三步:
1.先得到一条Stream流(流水线),并把数据放上去
2.使用中间方法对流水线上的数据进行操作
3.使用终结方法对流水线上的数据进行操作
让我们来一步步介绍
①得到一条Stream流(流水线),并把数据放上去
获取方式 | 方法名 | 说明 |
单列集合 | default Stream<E>stream() | Collection中的默认方法 |
双列集合 | 无 | 无法直接使用Stream流 |
数组 | public static<T>Stream<T>stream(T[]array) | Arrays工具类中的静态方法 |
一堆零散数据 | public static<T>Stream<T>of(T...values) | Stream接口中的静态方法 |
方法演示:
package StreamDemo;import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.function.Consumer;
import java.util.stream.Stream;public class demo1 {public static void main(String[] args) {ArrayList<String> list=new ArrayList<>();Collections.addAll(list,"a","b","c","d","e");Stream<String> stream = list.stream();//ctrl+v自动生成左边list.stream().forEach(s->{System.out.println(s);});//双列集合获取Stream流时必须利用keySet()或者entrySet()方法获取单列集合,然后再获取流HashMap<String,Integer> hm=new HashMap<>();hm.put("aaa",111);hm.put("bbb",222);hm.keySet().stream().forEach(s->System.out.println(s));hm.entrySet().stream().forEach(s->System.out.println(s.getKey()));int []arr={1,2,3,4,5,6};Arrays.stream(arr).forEach(s->System.out.println(s));//Stream接口中静态方法of的细节//方法形参是一个可变参数,可以传递一堆零散数据,也可以传递数组//但是数组必须是引用数据类型,如果传递基本数据类型,会把整个数组当作一个元素,放入Stream中Stream.of(arr).forEach(s->System.out.println(s));String []arr2={"a","b","c"};Stream.of(arr2).forEach(s->System.out.println(s));}
}
运行结果:
aaa
bbb
aaa
bbb
1
2
3
4
5
6
[I@7699a589
a
b
c
②使用中间方法对流水线上的数据进行操作
名称 | 说明 |
Stream<T>filter(Predicate<?super T>) predicate | 过滤 |
Stream<T>limit(long maxSize) | 获取前几个元素 |
Stream<T>skip(long n) | 跳过前几个元素 |
Stream<T>distinct | 元素去重 |
static<T>Stream<T>concat(Stream a,Stream b) | 合并a和b为一个流 |
static<R>map(Function<T,R> mapper) | 转换流中的数据类型 |
注意1:中间方法,返回新的Stream流,原来的Stream流只能使用一次,建议使用链式编程
注意2:修改Stream流中数据,不会影响原来的集合或者数组中的数据
代码演示:
package StreamDemo;import java.util.ArrayList;
import java.util.Collections;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.stream.Stream;public class demo3 {public static void main(String[] args) {ArrayList<String> list=new ArrayList<>();Collections.addAll(list,"张无忌","周芷若","赵敏","张强","张三丰","张翠三","张良","王二麻子","谢广坤");//1.filter 过滤,把张开头的留下,其余过滤不变System.out.print("filter:把张开头的留下");Stream<String> stream = list.stream();stream.filter(new Predicate<String>() {@Overridepublic boolean test(String s) {//如果为true,则把当前数据的留下//如果为false,则把当前数据舍弃return s.startsWith("张");}}).forEach(s->System.out.print(s+" "));System.out.println();//把姓张且长度为3进行过滤//以下的方法会报错 stream has already been operated upon or closed :正好验证了注意1:中间方法,返回新的Stream流,原来的Stream流只能使用一次,建议使用链式编程//stream.filter(s->s.length()==3).forEach(s->System.out.println(s));//那么我们试试链式编程System.out.print("filter链式编程:");list.stream().filter(s->s.startsWith("张")).filter(s->s.length()==3).forEach(s->System.out.print(s+" "));System.out.println();System.out.print("集合里面的数据:");System.out.println(list);//注意2:修改Stream流中数据,不会影响原来的集合或者数组中的数据//limit 获取前三个元素System.out.print("limit 获取前三个元素");list.stream().limit(3).forEach(s->System.out.print(s+" "));System.out.println();System.out.print("skip 跳过前几个元素:");list.stream().skip(3).forEach(s->System.out.print(s+" "));System.out.println();System.out.print("去重之后:");ArrayList<String> list2=new ArrayList();Collections.addAll(list2,"张无忌","张无忌","张无忌","张无忌","张无忌","张无忌","张无忌","王二麻子","谢广坤");//distinct 去重 看源码可以知道distinct底层时hashSetlist2.stream().distinct().forEach(s->System.out.print(s+" "));//concat 合并两个流System.out.println("concat 合并两个流:");Stream.concat(list.stream(),list2.stream()).forEach(s->System.out.print(s+" "));System.out.println();//map转换流中的数据类型System.out.print("stream.map转换数据类型 获取集合中的年龄:");ArrayList<String> list3=new ArrayList<>();Collections.addAll(list3,"张无忌-13","周芷若-14","赵敏-15","张强-16","张三丰-15");list3.stream().map(new Function<String, Integer>() {//函数式接口@Overridepublic Integer apply(String s) {String []arr=s.split("-");int x=Integer.parseInt(arr[1]);return x;}}).forEach(s->System.out.print(s+" "));System.out.println();}
}
运行结果:
filter:把张开头的留下张无忌 张强 张三丰 张翠三 张良
filter链式编程:张无忌 张三丰 张翠三
集合里面的数据:[张无忌, 周芷若, 赵敏, 张强, 张三丰, 张翠三, 张良, 王二麻子, 谢广坤]
limit 获取前三个元素张无忌 周芷若 赵敏
skip 跳过前几个元素:张强 张三丰 张翠三 张良 王二麻子 谢广坤
去重之后:张无忌 王二麻子 谢广坤 concat 合并两个流:
张无忌 周芷若 赵敏 张强 张三丰 张翠三 张良 王二麻子 谢广坤 张无忌 张无忌 张无忌 张无忌 张无忌 张无忌 张无忌 王二麻子 谢广坤
stream.map转换数据类型 获取集合中的年龄:
13 14 15 16 15
③Stream流中的终结方法
名称 | 说明 |
void forEach(Consumer action) | 遍历 |
long count() | 统计 |
toArray() | 收集流中的数据,放到数组中 |
collect(Collector collector) | 收集流中的数据,放到集合中 |
package StreamDemo;import java.util.*;
import java.util.function.Function;
import java.util.function.IntFunction;
import java.util.function.Predicate;
import java.util.stream.Collectors;public class demo4 {public static void main(String[] args) {System.out.println("forEach获取流中的每一个数据");ArrayList<String> list=new ArrayList<>();Collections.addAll(list,"张无忌","周芷若","赵敏","张强","张三丰","张翠三","张良","王二麻子","谢广坤");list.stream().forEach(s->System.out.print(s+" "));System.out.println();System.out.println("count统计流中的数据个数:");System.out.print(list.stream().count());System.out.println();System.out.println("收集流中的数据,放到数组里");//apply的形参:流中数据的个数String []arr=list.stream().toArray(new IntFunction<String[]>() {@Overridepublic String[] apply(int value) {return new String[value];}});System.out.print(Arrays.toString(arr));System.out.println();ArrayList<String> list3=new ArrayList<>();Collections.addAll(list3,"张无忌-13-男","周芷若-14-女","赵敏-15-女","张强-16-男","张三丰-15-男","张三丰-15-男");System.out.println("collect方法收集流中的数据并把其放入集合中");//获取到所有的男性,并把其放到集合中List<String> list4=list3.stream().filter(new Predicate<String>() {@Overridepublic boolean test(String s) {return s.split("-")[2].equals("男");}}).collect(Collectors.toList());System.out.println("收集到list集合中:"+list4);//放入Set集合Set<String> set=list3.stream().filter(new Predicate<String>() {@Overridepublic boolean test(String s) {return s.split("-")[2].equals("男");}}).collect(Collectors.toSet());System.out.println("收集到set集合中:"+set);//收集到map集合中 键姓名 值男性/*toMap:参数一表示键的生成规则参数二表示值的生成规则参数一:Function泛型一:表示流中每一个数据的类型泛型二:表示map集合中键的数据类型方法apply形参:依次表示流里面的每一个数据方法体:生成键的代码返回值:已经生成的键参数二:Function泛型一:表示流中每一个数据的类型泛型二:表示map集合中值的数据类型方法apply形参:依次表示流里面的每一个数据方法体:生成值的代码返回值:已经生成的值*/ArrayList<String> list5=new ArrayList<>();Collections.addAll(list5,"张无忌-13-男","周芷若-14-女","赵敏-15-女","张强-16-男","张三丰-15-男");//注意点//键不能重复,不然会报错Map<String,String> map=list5.stream().filter(new Predicate<String>() {@Overridepublic boolean test(String s) {return s.split("-")[2].equals("男");}}).collect(Collectors.toMap(new Function<String, String>() {@Overridepublic String apply(String s) {return s.split("-")[0];}}, new Function<String, String>() {@Overridepublic String apply(String s) {return s.split("-")[2];}}));//写键的规则和值的规则System.out.println("收集到,map集合中:"+map);}}
运行结果:
forEach获取流中的每一个数据
张无忌 周芷若 赵敏 张强 张三丰 张翠三 张良 王二麻子 谢广坤
count统计流中的数据个数:
9
收集流中的数据,放到数组里
[张无忌, 周芷若, 赵敏, 张强, 张三丰, 张翠三, 张良, 王二麻子, 谢广坤]
collect方法收集流中的数据并把其放入集合中
收集到list集合中:[张无忌-13-男, 张强-16-男, 张三丰-15-男, 张三丰-15-男]
收集到set集合中:[张强-16-男, 张三丰-15-男, 张无忌-13-男]
收集到,map集合中:{张强=男, 张三丰=男, 张无忌=男}
内容来自Stream流-02-Stream流的思想和获取Stream流_哔哩哔哩_bilibili