一.学习Stream流之前,我们先看一下下面这个问题
任务要求:有如下一个ArrayList集合,只要名字为3个字的成员姓名,筛选之后且只要前三个人
List<String> one = new ArrayList<>();
one.add("迪丽热巴");
one.add("孙悟空");
one.add("猪八戒");
one.add("古力娜扎");
one.add("洪七公");
one.add("唐三藏");
1.使用传统的实现方法如下:
// 将集合进行筛选,只要名字为3个字的成员姓名,并且只要前三个人
List<String> one1 = new ArrayList<>();
for (String name : one) {
if (name.length() == 3){
one1.add(name);
}
}
List<String> one2 = new ArrayList<>();
for (int i = 0; i < 3; i++) {
one2.add(one1.get(i));
}
System.out.println(one2);
2.使用Stream实现如下:
Stream<String> oneStream = one.stream().filter(name -> name.length() == 3).limit(3);
oneStream.forEach((p) ->{
System.out.println(p);
});
System.out.println(oneStream);
二.什么是Stream流?
(1)Stream流是JDK1.8之后出现的,Stream流其实是一个集合元素的函数模型,他并不是集合,也不是数据结构,其本身并不会存储任何元素(或地址值)
(2)Stream流属于管道流,只能被使用一次,当一个Stream流使用过后,就不能再调用方法了
// 创建一个stream流
Stream<String> stream = Stream.of("马云", "王健林", "马化腾");
// 对Stream流中的元素进行过滤,只要姓马的人
Stream<String> stream1 = stream.filter((String name) -> {
return name.startsWith("马");
});
// 遍历Stream流
stream1.forEach(name -> System.out.println(name));
//Stream是管道流,下面这个会报IllegalStateException: stream has already been operated upon or closed异常
stream.forEach(name -> System.out.println(name));
三.Stream流的获取
1.获取Stream流
(1)所有的Collections集合都可以通过stream或parallelStream方法获取流;
default Stream stream()
default Stream parallelStream()
ArrayList<Object> list = new ArrayList<>();
Stream<Object> stream = list.parallelStream();
(2) Stream接口的静态方法of可以获取数组对应的流
static Stream of(T values)
注:参数是一个可变参数,那么我们就可以传递一个数组.
// 把集合转换为Stream流
List<String> list = new ArrayList<>();
Stream<String> stream1 = list.stream();
// Map集合可以间接转换为Stream
Map<String,String> map = new HashMap<>();
// 获取键,存储到一个set集合中
Set<String> keySet = map.keySet();
Stream<String> stream2 = keySet.stream();
// 获取值,存储到一个Collection集合中
Collection<String> values = map.values();
Stream<String> stream3 = values.stream();
// 获取键值对(键与值的映射关系 entrySet)
Set<Map.Entry<String, String>> entries = map.entrySet();
Stream<Map.Entry<String, String>> stream4 = entries.stream();
// 把数组转换为Stream流
Stream<Integer> stream5 = Stream.of(1, 2, 7, 9);
// 可变参数可以传递数组
Integer[] arr = {2,3,4,6};
Stream<Integer> stream6 = Stream.of(arr);
四.Stream流的常用方法
1.void forEach(Consumer<? super T> action)
该方法接收一个Consumer接口函数,会将每一个流元素交给该函数进行处理
Consumer接口是一个消费型的函数式接口,可以传递Lambda表达式,消费数据
简言之:foreach方法就是用来遍历流中的数据,并且是一个终结方法,遍历之后就不能继续调用Stream流中的其他方法
// 获取一个Stream流
Stream<String> stream = Stream.of("亚瑟", "李白", "鲁班");
// 使用Stream流中的方法forEach对Stream流中的数据进行遍历
stream.forEach((String name) ->{
System.out.println(name);}
2.Stream filter(Predicate<? super T> predicate)
filter方法的参数Predicate是一个函数式接口,可以传递Lambda表达式,对数据进行过滤
// 创建一个stream流
Stream<String> stream = Stream.of("马云", "王健林", "马化腾");
// 对Stream流中的元素进行过滤,只要姓马的人
Stream<String> stream1 = stream.filter((String name) -> {
return name.startsWith("马");
});
// 遍历Stream流
stream1.forEach(name -> System.out.println(name));
3. Stream map(Function<? super T, ? extends R> mapper);
map方法可以将流中的元素映射到另一个流中,该接口需要一个Function函数式(函数型接口)接口参数,可以将流中的T类型转换
为另一种R类型的流。
// 获取一个String类型的Stream流
Stream<String> stream = Stream.of("1", "2", "4", "6");
// 使用map方法,把字符串类型的整数,转换(映射)为Integer类型的整数
Stream<Integer> stream1 = stream.map((String s) -> {
return Integer.parseInt(s);
});
// 遍历Stream流
stream1.forEach(i -> System.out.println(i));
补充:
(1)map:接收Lambda,将元素转换成其他形式或提取信息。接收一个函数作为参数,该函数会被应用到每个元素上,并将其
映射成一个新的元素
(2)flatMap:接收一个函数作为参数,将流中的每个值都转换成另一个流,然后把所有流连接成一个流
4.Stream limit(long maxSize);
用于截取流中的元素,参数是一个long类型,如果集合当前长度大于参数进行截取,否则不进行操作
limit方法是一个延迟方法,只是对流中的元素进行截取,返回的是一个新的流,所以可以继续调用Stream流中的其他方法
Stream<String> stream = Stream.of("胡歌", "彭于晏", "马天宇","刘德华");
Stream<String> stream1 = stream.limit(3);
stream1.forEach(name -> System.out.println(name));
5.Stream skip(long n);
用于跳过前几个元素,可以使用skip方法获取一个截取之后的新流;
如果流的长度大于n,则跳过前n个元素;否则将会得到一个长度为0的空流
Stream<Integer> stream = Stream.of(1, 2, 4, 9);
Stream<Integer> stream1 = stream.skip(2);
stream1.forEach(name -> System.out.println(name));
6.public static Stream concat(Stream<? extends T> a, Stream<? extends T> b)
用于把流组合到一起
Stream<String> stream1 = Stream.of("周星驰", "李小龙", "成龙");
Stream<String> stream2 = Stream.of("胡歌", "彭于晏");
Stream<String> stream = Stream.concat(stream1, stream2);
stream.forEach(name -> System.out.println(name));
7.排序
(1)sorted()——自然排序(Comparable,按照字典排)
(2)sorted(Comparator com)——定制排序(Comparator)
8.终止操作
(1)allMatch——检查是否匹配所有元素
(2)anyMatch——检查是否至少匹配一个元素
(3)noneMatch——检查是否没有匹配所有元素
(4)findFirst——返回第一个元素
(5)findAny——返回当前流中的任意元素
(6)count——返回流中元素的总个数
(7)max——返回流中最大值
(8)min——返回流中最小值
9.规约
T reduce(T identity, BinaryOperator<T> accumulator)
:可以将流中元素反复结合起来,得到一个值,返回T
Optional<T> reduce(BinaryOperator<T> accumulator)
:可以将流中元素反复结合起来,得到一个值,返回Optional<T>
List<Integer> list = Arrays.asList(1, 2, 3, 4, 5);
Integer sum = list.stream()
.reduce(0, (x, y) -> x + y);//得到总和
// 先把0作为x,y作为1,x+y=1;再把结果1作为x
System.out.println(sum);
10.收集
collect(Collcetor c) 方法,收集流中的数据到【集合】或者【数组】中去。
Collector接口中方法的实现决定了如何对流执行收集操作(如收集到List、Set、Map)。但是Collectors实用类提供了
很多静态方法,可以方便的创建常见收集器实例
//1.收集数据到list集合中
stream.collect(Collectors.toList())
//2.收集数据到set集合中
stream.collect(Collectors.toSet())