# stream流
# 初识stream流
创建集合元素,完成以下需求,
- 把所有“张”开头的元素存储到新集合中
- 把“张”开头的元素,长度为3的元素存储到新集合中
- 遍历打印最终结果
package stream;
import java.util.ArrayList;
public class Main {
public static void main(String[] args) {
// 创建集合元素,完成以下需求,
//
// 1. 把所有“张”开头的元素存储到新集合中
// 2. 把“张”开头的元素,长度为3的元素存储到新集合中
// 3. 遍历打印最终结果
ArrayList<String> list = new ArrayList<>();
list.add("张无忌");
list.add("张翠山");
list.add("张良");
list.add("王二麻子");
list.add("谢广坤");
list.add("张三丰");
//1.把所有以张开头的元素存储到新集合中
ArrayList<String> list1 = new ArrayList<>();
list.forEach(s -> {
if (s.startsWith("张")) list1.add(s);
});
System.out.println(list1);
//2.把张开头而且长度为3的元素存储到新集合中
ArrayList<String> list2 = new ArrayList<>();
list1.forEach(s -> {
if (s.length() == 3) list2.add(s);
});
System.out.println(list2);
//使用stream流
list.stream().filter(s -> s.length() == 3 && s.startsWith("张")).forEach(System.out::println);
}
}
# Stream流的使用步骤
- 创建一个
Stream流(流水线),并把数据放上去
| 获取方式 | 方法名 | 说明 |
|---|---|---|
| 单列集合 | default Stream<E> stream() | Collection中的默认方法 |
| 双列集合 | 无 | 无法使用 |
| 数组 | public static<T> Stream<T> stream(T... values) | Arrays工具类中的静态方法 |
| 一堆零散数据 | public static<T> Stream<T> of(T... values) | stream接口中的静态方法 |
# 单列集合获取stream流
package stream;
import java.util.ArrayList;
import java.util.Collections;
import java.util.stream.Stream;
public class StreamDemo {
public static void main(String[] args) {
//1.单列集合获取stream流
ArrayList<String> list3 = new ArrayList<>();
Collections.addAll(list3, "张无忌", "张翠山", "张良", "王二麻子", "谢广坤", "张三丰");
//获取一条流水线 并把数据放在流水线上
Stream<String> stream = list3.stream();
//使用终结方法打印以下流水线上的所有数据
//stream流的每一条数据本质上是一个Consumer数据 hi用匿名内部类依次打印
// stream.forEach(new Consumer<String>() {
// @Override
// public void accept(String s) {
// System.out.println(s);
// }
// });
//简化方法(stream流只能使用一次)
stream.forEach(System.out::println);
}
}
# 双列集合获取stream流
package stream;
import java.util.*;
public class StreamDemo2 {
public static void main(String[] args) {
//双列集合获取stream流
//在双列集合中不能直接获取stream流 但是可以将双列集合转化为单列集合
//创建双列集合
HashMap<String, String> map = new HashMap<>();
//添加数据
map.put("001", "张无忌");
map.put("002", "张翠山");
map.put("003", "张良");
map.put("004", "王二麻子");
map.put("005", "谢广坤");
map.put("006", "张三丰");
//第一种方法 获取双列集合中所有的key 并存入一个set集合中 获取stream流(借助keySet)借助keySet
Stream<String> stream1 = map.keySet().stream();
//打印流水线中的元素
stream1.forEach(System.out::println);
System.out.println("----------------------------------------------------------------------------------------");
//第二种方法
//获取双列集合中所有的键值对对象 并存入单列集合中
Set<Map.Entry<String, String>> set = map.entrySet();
System.out.println(set);//[001=张无忌, 002=张翠山, 003=张良, 004=王二麻子, 005=谢广坤, 006=张三丰]
//获取stream流
Stream<Map.Entry<String, String>> stream2 = set.stream();
//遍历
stream2.forEach(System.out::println);
}
}
# 数组获取stream流
package stream;
import java.util.*;
import java.util.stream.Stream;
public class StreamDemo3 {
public static void main(String[] args) {
//数组获取stream流
String[] arr = {"张无忌", "张翠山", "张良", "王二麻子", "谢广坤", "张三丰"};
Arrays.stream(arr).forEach(System.out::println);
}
}
# 零散数据获取stream流
package stream;
import java.util.*;
import java.util.stream.Stream;
public class StreamDemo4 {
public void main(String[] args) {
//一堆零散的数据获取stream流
//前提所有放入流水线的数据类型要一致
Stream.of("张无忌", "张翠山", "张良", "王二麻子", "谢广坤", "张三丰").forEach(System.out::println);
}
}
注意
- stream流只能使用一次,使用后流就关闭了,再次使用会报错。
- 零散数据获取stream流时,可以传递整个数组,但只能传递引用数据类型的数组,如果传递基本数据类型,是会把整个数组当作一个元素,放到stream流中
# stream流中的中间方法
| 名称 | 说明 |
|---|---|
stream<T> filter(Predicate<? super T> predicate) | 过滤数据 |
stream<T> distinct() | 去重,依赖(hashCode()和equals()) |
stream<T> limit(long maxSize) | 获取前几个元素 |
stream<T> skip(long n) | 跳过前n个元素 |
static <T> Stream<T> concat(Stream<? extends T> a, Stream<? extends T> b) | 合并两个流 |
stream<T> map(Function<? super T, ? extends R> mapper) | 将元素转换成其他形式或提取信息,接收一个函数作为参数,该函数会被应用到每个元素上,并将其映射成一个新的元素。 |
注意
- 中间方法返回新的
Stream流,原来的stream流只能使用一次,建议使用链式编程 - 修改
stream流中的数据,不会影响原来集合或者数组中的数据 - 使用
concat合并两个流时尽量保持两个流的累心一致,否则输出会去两个类的父类类型
package stream;
import java.util.*;
import java.util.stream.Stream;
public class StreamDemo5 {
public static void main(String[] args) {
//stream流中的中间方法
// 1. filter() 过滤
ArrayList<String> list4 = new ArrayList<>();
Collections.addAll(list4, "张无忌", "张翠山", "张良", "张良", "谢广坤", "张三丰");
list4.stream().filter(s -> s.startsWith("张")).forEach(System.out::println);
// 2. limit() 获取前几个元素
list4.stream().limit(3).forEach(System.out::println);
// 3. skip() 跳过前几个元素
list4.stream().skip(3).forEach(System.out::println);
// 4. distinct() 去重
list4.stream().distinct().forEach(System.out::println);
// 6. 自定义去重
System.out.println("----------------------------------------------------------------------------------------");
ArrayList<pople> list5 = new ArrayList<>();
Collections.addAll(list5, new pople("张无忌", 18), new pople("张三", 18), new pople("张三", 18), new pople("王五", 30));
list5.stream().distinct().forEach(s -> System.out.println(s.name));
// 7.合并两个流
System.out.println("----------------------------------------------------------------------------------------");
ArrayList<String> list6 = new ArrayList<>();
Collections.addAll(list6, "张无忌", "张翠山", "张良", "王二麻子", "谢广坤", "张三丰");
ArrayList<String> list7 = new ArrayList<>();
Collections.addAll(list7, "张无忌", "张翠山", "张良", "王二麻子", "谢广坤", "张三丰");
Stream<String> stream3 = Stream.concat(list6.stream(), list7.stream());
stream3.forEach(System.out::println);
//8.map 改变流中的数据类型
System.out.println("----------------------------------------------------------------------------------------");
ArrayList<String> list8 = new ArrayList<>();
Collections.addAll(list8, "张无忌-10", "张翠山-20", "张良-30", "王二麻子-40", "谢广坤-50", "张三丰-60");
list8.stream().map(new Function<String, Integer>() {
@Override
//apply(s 代表流中的每一个数据) 返回值表示要转换的类型 并且不能是基本数据类型 必须是引用类型
public Integer apply(String s) {
String[] split = s.split("-");
return parseInt(split[1]);
}
}).forEach(System.out::println);
//简化形式
list8.stream().map(s -> Integer.parseInt(s.split("-")[1])).forEach(System.out::println);
}
static class pople {
String name;
int age;
public pople(String name, int age) {
this.name = name;
this.age = age;
}
//年龄相同代表重复
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
pople pople = (pople) o;
return age == pople.age;
}
@Override
public int hashCode() {
return Objects.hash(age);
}
}
}
# stream流的终结方法
| 名称 | 说明 |
|---|---|
void forEach(Consumer<? super T> action) | 遍历流中的元素 |
long count() | 统计流中元素个数 |
toArray() | 收集流中的数据,放到数组中 |
collect(Collector<? super T, A, R> collector) | 收集流中的数据放到集合中 |
package stream;
import java.util.*;
import java.util.stream.Stream;
public class StreamDemo6 {
public static void main(String[] args) {
//遍历forEach()
list8.stream().forEach(System.out::println);
//统计count()
System.out.println(list8.stream().count());
//收集流中的数据放到数组中
//toArray无形参方法
Object[] arr2 = list8.stream().toArray();
System.out.println(Arrays.toString(arr2));
//带形参方法
//IntFunction 具体类型的数组
//IntFunction<? extends T[]> 泛型数组
//apply:流中数据的个数,要跟数组的长度保持一致
//apply返回值表示要转换的类型
//方法体就是创建数组
//toArray 创建指定类型的数组,
//底层 会依次得到流里面的每一个数据,并把数据放到数组当中
//toArray的返回值是一个装着流里面所有数据的数组
String[] arr3 = list8.stream().toArray(new IntFunction<String[]>() {
@Override
public String[] apply(int value) {
System.out.println("value = " + value);//value = 6
//创建具体类型的数组
return new String[value];
}
});
System.out.println(Arrays.toString(arr3));
//简化写法
String[] arr4 = list8.stream().toArray(s -> new String[s]);
System.out.println(Arrays.toString(arr4));
}
}
# stream收集方法collect
使用collect函数可以收集流中的数据,放到List、Set、Map等集合中。
package stream;
import java.util.*;
import java.util.stream.Stream;
public class StreamDemo7 {
public static void main(String[] args) {
//stream收集方法 收集到集合中
ArrayList<String> list9 = new ArrayList<>();
Collections.addAll(list9, "张无忌-男-18", "张翠山-男-19", "张良-女-20", "王二麻子-男-21", "谢广坤-男-22", "张三丰-男-23");
//需求收集所有的男性
//收集到list集合中
List<String> list10 = list9.stream().filter(s -> s.split("-")[1].equals("男")).collect(Collectors.toList());
System.out.println(list10);
//收集到set集合中(set集合不重复)
Set<String> setList = list9.stream().filter(s -> s.split("-")[1].equals("男")).collect(Collectors.toSet());
System.out.println(setList);
//收集到map集合中(谁作为键,谁做为值)
//toMap
//参数1:键的生成规则
//参数2:值的生成规则
Map<String, String> stringMap = list9.stream().filter(s -> s.split("-")[1].equals("男")).collect(Collectors.toMap(s -> s.split("-")[0], s -> s.split("-")[2]));
System.out.println(stringMap);
}
}
# stream流综合练习
# 数据过滤
定义一个集合,并添加一些整数 过滤奇数只留下偶数,并把结果收集起来
package stream;
public class StreamDemo8 {
public static void main(String[] args) {
ArrayList<Integer> list11 = new ArrayList<>();
Collections.addAll(list11, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
List<Integer> list12 = list11.stream().filter(s -> s % 2 == 0).toList();
System.out.println(list12);//[2, 4, 6, 8, 10]
}
}
创建一个ArrayList集合,并添加一些字符串,字符串前面是姓名后面是年龄
保留年龄大于24的人,并将结果收集到map集合中,姓名为键,年龄为值
package stream;
public class StreamDemo9 {
public static void main(String[] args) {
ArrayList<String> list13 = new ArrayList<>();
Collections.addAll(list13, "张无忌-18", "张翠山-19", "张良-20", "王二麻子-21", "谢广坤-22", "张三丰-23");
Map<String, Integer> map1 = list13.stream().map(s -> {
String[] split = s.split("-");
return new String[]{split[0], split[1]};
}).filter(s -> parseInt(s[1]) > 18).collect(Collectors.toMap(s -> s[0], s -> parseInt(s[1])));
System.out.println(map1);
}
}