Sream流
- 1 Stream流初体验
- 2 Stream流概述
- 3 生成Stream流
- 4 中间操作方法
- 5 终结操作方法
- 6 收集操作方法
- 7 Stream流案例
1 Stream流初体验
- 案例需求
- 创建一个集合,存储多个字符串元素
- 把集合中所有以“张”开头的元素存储到一个新的集合
- 把"张"开头的集合中的长度为3的元素存储到一个新的集合
- 遍历上一步得到的集合
- 示例代码
public static void main(String[] args) {
//集合的批量添加
ArrayList<String> list1 = new ArrayList<>(List.of("张三丰","张无忌","张翠山","王二麻子","张良","谢广坤"));
//list.add()
//遍历list1把以张开头的元素添加到list2中。
ArrayList<String> list2 = new ArrayList<>();
for (String s : list1) {
if(s.startsWith("张")){
list2.add(s);
}
}
//遍历list2集合,把其中长度为3的元素,再添加到list3中。
ArrayList<String> list3 = new ArrayList<>();
for (String s : list2) {
if(s.length() == 3){
list3.add(s);
}
}
for (String s : list3) {
System.out.println(s);
}
System.out.println("=======================");
//Stream流
list1.stream().filter(s->s.startsWith("张"))
.filter(s->s.length() == 3)
.forEach(s-> System.out.println(s));
}
注意:
List.of
是JDK9及以后的
2 Stream流概述
- Stream流的好处
- 直接阅读代码的字面意思即可完美展示无关逻辑方式的语义
- Stream流把真正的函数式编程风格引入到Java中
- 代码简洁
- Stream流的三类方法
- 获取Stream流
- 创建一条流水线,并把数据放到流水线上准备进行操作
- 中间方法
- 流水线上的操作
- 一次操作完毕之后,还可以继续进行其他操作
- 终结方法
- 一个Stream流只能有一个终结方法
- 是流水线上的最后一个操作
- 获取Stream流
3 生成Stream流
- Collection体系集合
- 使用默认方法stream()生成流,
default Stream<E> stream()
- 使用默认方法stream()生成流,
- Map体系集合
- 把Map转成Set集合,间接的生成流
- 数组
- 通过Arrays中的静态方法stream生成流
- 同种数据类型的多个数据
- 通过Stream接口的静态方法of(T… values)生成流
public static void main(String[] args) {
//单列集合
//method1();
//双列集合
//method2();
//数组
//method3();
//同种数据类型的多个数据
//method4();
}
private static void method4() {
Stream.of(1,2,3,4,5,6,7,8).forEach(s-> System.out.println(s));
}
private static void method3() {
int [] arr = {1,2,3,4,5};
Arrays.stream(arr).forEach(s-> System.out.println(s));
}
private static void method2() {
HashMap<String,Integer> hm = new HashMap<>();
hm.put("zhangsan",23);
hm.put("lisi",24);
hm.put("wangwu",25);
hm.put("zhaoliu",26);
hm.put("qianqi",27);
//双列集合不能直接获取Stream流
//1.keySet
//先获取到所有的键
//再把这个Set集合中所有的键放到Stream流中
//hm.keySet().stream().forEach(s-> System.out.println(s));
//2.entrySet
//先获取到所有的键值对对象
//再把这个Set集合中所有的键值对对象放到Stream流中
hm.entrySet().stream().forEach(s-> System.out.println(s));
}
private static void method1() {
ArrayList<String> list = new ArrayList<>();
list.add("aaa");
list.add("bbb");
list.add("ccc");
// Stream<String> stream = list.stream();
// stream.forEach(s-> System.out.println(s));
list.stream().forEach(s-> System.out.println(s));
}
4 中间操作方法
中间操作的意思是,执行完此方法之后,Stream流依然可以继续执行其他操作
filter方法
public static void main(String[] args) {
// Stream<T> filter(Predicate predicate):过滤
// Predicate接口中的方法 boolean test(T t):对给定的参数进行判断,返回一个布尔值
ArrayList<String> list = new ArrayList<>();
list.add("张三丰");
list.add("张无忌");
list.add("张翠山");
list.add("王二麻子");
list.add("张良");
list.add("谢广坤");
//filter方法获取流中的 每一个数据.
//而test方法中的s,就依次表示流中的每一个数据.
//我们只要在test方法中对s进行判断就可以了.
//如果判断的结果为true,则当前的数据留下
//如果判断的结果为false,则当前数据就不要.
// list.stream().filter(
// new Predicate<String>() {
// @Override
// public boolean test(String s) {
// boolean result = s.startsWith("张");
// return result;
// }
// }
// ).forEach(s-> System.out.println(s));
//因为Predicate接口中只有一个抽象方法test
//所以我们可以使用lambda表达式来简化
// list.stream().filter(
// (String s)->{
// boolean result = s.startsWith("张");
// return result;
// }
// ).forEach(s-> System.out.println(s));
list.stream().filter(s ->s.startsWith("张")).forEach(s-> System.out.println(s));
}
其他中间方法
public static void main(String[] args) {
ArrayList<String> list = new ArrayList<>();
list.add("张三丰");
list.add("张无忌");
list.add("张翠山");
list.add("王二麻子");
list.add("张良");
list.add("谢广坤");
list.add("谢广坤");
list.add("谢广坤");
list.add("谢广坤");
list.add("谢广坤");
//method1(list);
//method2(list);
//method3();
//method4(list);
}
private static void method4(ArrayList<String> list) {
// Stream<T> distinct():去除流中重复的元素。依赖(hashCode和equals方法)
list.stream().distinct().forEach(s-> System.out.println(s));
}
private static void method3() {
//static <T> Stream<T> concat(Stream a, Stream b):合并a和b两个流为一个流
ArrayList<String> list = new ArrayList<>();
list.add("张三丰");
list.add("张无忌");
list.add("张翠山");
list.add("王二麻子");
list.add("张良");
list.add("谢广坤");
list.add("谢广坤");
list.add("谢广坤");
list.add("谢广坤");
list.add("谢广坤");
ArrayList<String> list2 = new ArrayList<>();
list2.add("张三丰");
list2.add("张无忌");
list2.add("张翠山");
list2.add("王二麻子");
list2.add("张良");
list2.add("谢广坤");
// Stream<String> stream1 = list.stream();
// Stream<String> stream2 = list2.stream();
//
// Stream<String> stream3 = Stream.concat(stream1, stream2);
// stream3.forEach(s-> System.out.println(s));
Stream.concat(list.stream(),list2.stream()).forEach(s-> System.out.println(s));
}
private static void method2(ArrayList<String> list) {
// Stream<T> skip(long n):跳过指定参数个数的数据
list.stream().skip(2).forEach(s-> System.out.println(s));
}
private static void method1(ArrayList<String> list) {
// Stream<T> limit(long maxSize):截取指定参数个数的数据
list.stream().limit(2).forEach(s-> System.out.println(s));
}
5 终结操作方法
终结操作的意思是,执行完此方法之后,Stream流将不能再执行其他操作
public static void main(String[] args) {
ArrayList<String> list = new ArrayList<>();
list.add("张三丰");
list.add("张无忌");
list.add("张翠山");
list.add("王二麻子");
list.add("张良");
list.add("谢广坤");
//method1(list);
// long count():返回此流中的元素数
long count = list.stream().count();
System.out.println(count);
}
private static void method1(ArrayList<String> list) {
// void forEach(Consumer action):对此流的每个元素执行操作
// Consumer接口中的方法 void accept(T t):对给定的参数执行此操作
//在forEach方法的底层,会循环获取到流中的每一个数据.
//并循环调用accept方法,并把每一个数据传递给accept方法
//s就依次表示了流中的每一个数据.
//所以,我们只要在accept方法中,写上处理的业务逻辑就可以了.
list.stream().forEach(
new Consumer<String>() {
@Override
public void accept(String s) {
System.out.println(s);
}
}
);
System.out.println("====================");
//lambda表达式的简化格式
//是因为Consumer接口中,只有一个accept方法
list.stream().forEach(
(String s)->{
System.out.println(s);
}
);
System.out.println("====================");
//lambda表达式还是可以进一步简化的.
list.stream().forEach(s->System.out.println(s));
}
6 收集操作方法
对数据使用Stream流的方式操作完毕后,可以把流中的数据收集到集合中
常用方法
工具类Collectors提供了具体的收集方式
/**
* Stream流的收集方法
* 练习:
* 定义一个集合,并添加一些整数1,2,3,4,5,6,7,8,9,10
* 将集合中的奇数删除,只保留偶数。
* 遍历集合得到2,4,6,8,10。
*/
public static void main(String[] args) {
ArrayList<Integer> list1 = new ArrayList<>();
for (int i = 1; i <= 10; i++) {
list1.add(i);
}
list1.add(10);
list1.add(10);
list1.add(10);
list1.add(10);
list1.add(10);
//filter负责过滤数据的.
//collect负责收集数据.
//获取流中剩余的数据,但是他不负责创建容器,也不负责把数据添加到容器中.
//Collectors.toList() : 在底层会创建一个List集合.并把所有的数据添加到List集合中.
List<Integer> list = list1.stream().filter(number -> number % 2 == 0)
.collect(Collectors.toList());
System.out.println(list);
Set<Integer> set = list1.stream().filter(number -> number % 2 == 0)
.collect(Collectors.toSet());
System.out.println(set);
// List和Set区别:Set有去重功能
}
/**
* Stream流的收集方法
*
* 创建一个ArrayList集合,并添加以下字符串。字符串中前面是姓名,后面是年龄
* "zhangsan,23"
* "lisi,24"
* "wangwu,25"
* 保留年龄大于等于24岁的人,并将结果收集到Map集合中,姓名为键,年龄为值
*/
public static void main(String[] args) {
ArrayList<String> list = new ArrayList<>();
list.add("zhangsan,23");
list.add("lisi,24");
list.add("wangwu,25");
Map<String, Integer> map = list.stream().filter(
s -> {
String[] split = s.split(",");
int age = Integer.parseInt(split[1]);
return age >= 24;
}
// collect方法只能获取到流中剩余的每一个数据.
//在底层不能创建容器,也不能把数据添加到容器当中
//Collectors.toMap 创建一个map集合并将数据添加到集合当中
// s 依次表示流中的每一个数据
//第一个lambda表达式就是如何获取到Map中的键
//第二个lambda表达式就是如何获取Map中的值
).collect(Collectors.toMap(
s -> s.split(",")[0],
s -> Integer.parseInt(s.split(",")[1]) ));
System.out.println(map);
}
注意:
- Stream流只能操作流中的数据,而无法直接修改集合、数组等数据源中的数据
7 Stream流案例
案例需求
现在有两个ArrayList集合,分别存储6名男演员名称和6名女演员名称,要求完成如下的操作
- 男演员只要名字为3个字的前三人
- 女演员只要姓林的,并且不要第一个
- 把过滤后的男演员姓名和女演员姓名合并到一起
- 把上一步操作后的元素作为构造方法的参数创建演员对象,遍历数据
标准类演员类(Actor)已存在
测试类
public static void main(String[] args) {
ArrayList<String> manList = new ArrayList<>();
manList.add("张国立");
manList.add("张晋");
manList.add("刘烨");
manList.add("郑伊健");
manList.add("徐峥");
manList.add("王宝强");
ArrayList<String> womanList = new ArrayList<>();
womanList.add("郑爽");
womanList.add("杨紫");
womanList.add("关晓彤");
womanList.add("张天爱");
womanList.add("杨幂");
womanList.add("赵丽颖");
//男演员只要名字为3个字的前两人
Stream<String> stream1 = manList.stream().filter(name -> name.length() == 3).limit(2);
//女演员只要姓杨的,并且不要第一个
Stream<String> stream2 = womanList.stream().filter(name -> name.startsWith("杨")).skip(1);
Stream.concat(stream1,stream2).forEach(name -> {
Actor actor = new Actor(name);
System.out.println(actor);
});
}