Stream流
Stream流的三类方法
-
获取Stream流
创建一条流水线,并把数据放到流水线上准备操作
-
中间方法
流水线上的操作
可以执行多个操作
-
终结方法
流水线的最后一个操作
一个Stream流只能有一个终结方法
Stream流的获取方法
Stream流可以使用在 单列集合
、双列集合
、数组
和同种数据类型多个数据
这四种情况下
-
单列集合
ArrayList<String> list = new ArrayList<>(List.of("a", "b", "c")); list.stream().forEach(s -> System.out.println(s)); // 输出结果 // a // b // c
-
双列集合
HashMap<String, String> hm = new HashMap<>(); hm.put("20001", "zhangsan"); hm.put("20002", "lisi"); hm.put("20003", "wangwu"); // 先获取所有的键,然后通过stream流输出键 hm.keySet().stream().forEach(s -> System.out.println(s)); // 输出结果 // 20003 // 20002 // 20001
HashMap<String, String> hm = new HashMap<>(); hm.put("20001", "zhangsan"); hm.put("20002", "lisi"); hm.put("20003", "wangwu"); // 先获取所有的键值对对象,然后通过stream流输出所有对象 hm.entrySet().stream().forEach(s -> System.out.println(s)); // 输出结果 // 20003=wangwu // 20002=lisi // 20001=zhangsan
-
数组
int[] arr= {1, 2, 3, 4, 5}; Arrays.stream(arr).forEach(s -> System.out.println(s)); // 输出结果 // 1 // 2 // 3 // 4 // 5
-
同种数据类型多个数据
Stream.of(1, 2, 3, 4, 5).forEach(s -> System.out.println(s)); // 输出结果 // 1 // 2 // 3 // 4 // 5
Stream流的中间操作常用方法
filter方法
Stream<T> filter(Predicate predicate)
:用于对流中数据进行过滤
Predicate
接口中只有一个抽象方法 boolean test(T t)
参数 t
为流中的每一个数据,该方法返回一个布尔值,如果返回的结果为 true
则当前数据留下,如果返回的结果为 false
则过滤掉当前数据
-
实现案例
-
使用匿名函数作为参数
ArrayList<String> list = new ArrayList<>(List.of("赵四", "赵围", "张三", "李四")); list.stream().filter(new Predicate<String>() { @Override public boolean test(String s) { Boolean result = s.startsWith("赵"); return result; } }).forEach(s -> System.out.println(s)); // 输出结果 // 赵四 // 赵围
-
使用lambda函数作为参数
因为Predicate接口中只有一个抽象方法 test,所以可以使用lambda表达式来达到简化代码的目的
ArrayList<String> list = new ArrayList<>(List.of("赵四", "赵围", "张三", "李四")); list.stream().filter((String s) -> { Boolean result = s.startsWith("赵"); return result; }).forEach(s -> System.out.println(s)); // 输出结果 // 赵四 // 赵围
-
简化lambda函数
ArrayList<String> list = new ArrayList<>(List.of("赵四", "赵围", "张三", "李四")); list.stream().filter(s -> s.startsWith("赵")).forEach(s -> System.out.println(s));
-
limit方法
Stream<T> limit(long maxSize)
:截取指定参数个数的数据
ArrayList<String> list = new ArrayList<>();
list.add("小明");
list.add("小鸿");
list.add("小红");
list.add("小华");
list.stream().limit(2).forEach(s -> System.out.println(s));
// 输出结果
// 小明
// 小鸿
skip方法
Stream<T> skip(long n)
:跳过指定参数个数的数据
ArrayList<String> list = new ArrayList<>();
list.add("小明");
list.add("小鸿");
list.add("小红");
list.add("小华");
list.stream().skip(2).forEach(s -> System.out.println(s));
// 输出结果
// 小红
// 小华
concat方法
static <T> Stream<T> concat(Stream a, Stream b)
:合并 a
和 b
两个流为一个流
ArrayList<String> list = new ArrayList<>();
list.add("小明");
list.add("小鸿");
list.add("小红");
list.add("小华");
ArrayList<String> list2 = new ArrayList<>();
list2.add("小花");
list2.add("小爱");
list2.add("小密");
list2.add("小五");
Stream.concat(list.stream(), list2.stream()).forEach(s -> System.out.println(s));
// 输出结果
// 小明
// 小鸿
// 小红
// 小华
// 小花
// 小爱
// 小密
// 小五
distinct方法
Stream<T> distinct()
:去除流中重复的元素,依赖(hashCode()
和equals()
方法)
ArrayList<String> list = new ArrayList<>();
list.add("小明");
list.add("小鸿");
list.add("小红");
list.add("小华");
list.add("小华");
list.add("小华");
list.stream().distinct().forEach(s -> System.out.println(s));
// 输出结果
小明
小鸿
小红
小华
Stream流的终结操作常用方法
forEach(Consumer action)
:对流的每个元素执行操作Consumer
接口中只有一个void accept(T t)
方法,该方法对给定的参数执行此操作
long count()
:返回流中的元素个数
forEach方法
-
匿名内部类传参
ArrayList<String> list = new ArrayList<>(List.of("1", "2", "3")); // 匿名内部类传参 list.stream().forEach(new Consumer<String>() { @Override public void accept(String s) { System.out.println(s); } }); // 输出结果 // 1 // 2 // 3
-
lambda
函数传参因为
Consumer
接口里只有一个抽象方法accept
,所以可以使用lambda
函数简化代替ArrayList<String> list = new ArrayList<>(List.of("1", "2", "3")); list.stream().forEach((String s) -> { System.out.println(s); }); // 输出结果 // 1 // 2 // 3
-
简化lambda函数
ArrayList<String> list = new ArrayList<>(List.of("1", "2", "3")); list.stream().forEach(s -> System.out.println(s)); // 输出结果 // 1 // 2 // 3
count方法
long count = list.stream().count();
System.out.println(count);
// 输出结果
// 3
Stream流的收集方法
通过stream
流获取到的集合、数组等类型的数据进行修改操作,但是源数据是没有改变的,我们无法直接修改源数据,但是我们可以使用相关方法对流中的数据进行保存
-
Stream流的收集方法
R collect(Collector collector)
-
工具类Collectors提供的具体收集方式
-
public static <T> Collector toList()
:把元素收集到List
集合中ArrayList<Integer> list = new ArrayList<>(List.of(1, 2, 3, 4, 5, 6, 7, 7, 7)); List<Integer> collectList = list.stream().filter(number -> number % 2 == 1).collect(Collectors.toList()); System.out.println(collectList); // [1, 3, 5, 7, 7, 7]
-
public static <T> Collector toSet()
:把元素收集到Set
集合中ArrayList<Integer> list = new ArrayList<>(List.of(1, 2, 3, 4, 5, 6, 7, 7, 7)); Set<Integer> collectSet = list.stream().filter(number -> number % 2 == 1).collect(Collectors.toSet()); System.out.println(collectSet); // [1, 3, 5, 7]
-
public static <T> Collector toMap(Function keyMapper, Function valueMapper)
:把元素收集到Map
集合中创建一个
ArrayList
集合,集合添加这些元素 “zhangsan,24”、“lisi,18”、“wangwu,26”、“zhaoliu,20” ,这些元素前面是姓名,后面是年龄;现需将里面的元素筛选出来,条件是年龄大于等于24岁的,并把帅选出来的数据保存到Map
集合中,姓名为键,年龄为值。ArrayList<String> list = new ArrayList<>(); list.add("zhangsan,24"); list.add("lisi,18"); list.add("wangwu,26"); list.add("zhaoliu,20"); Map<String, String> map = list.stream().filter(s -> { String[] split = s.split(","); int age = Integer.parseInt(split[1]); return age >= 24; }).collect(Collectors.toMap( s -> s.split(",")[0], s -> s.split(",")[1] )); System.out.println(map); // {zhangsan=24, wangwu=26}
toMap()
里的第一个lambda
表达式是如何获取Map
集合元素中的键,第二个lambda
表达式是如何获取Map
集合元素中的值
-
Stream流案例练习
现有两个 ArrayList
集合,分别存储5名男同学和5名女同学的名字,要求完成以下操作:
- 男同学只要名字为3个字的前三个人
- 女同学只要姓李的,并且跳过第一个人
- 将过滤后的男同学和女同学的姓名合并到一起
- 完成合并操作后得到的元素作为构造方法的参数创建学生对象,然后遍历数据
- 学生类
Student
,里面有一个成员变量,一个不带参数的构造方法,一个带参数构造方法,以及成员变量对应的get
和set
方法,还有toString()
方法
- 学生类
学生类
package com.cmy.streamdemo;
/**
* @author chenmingyong
*/
public class Student {
private String stuName;
public Student(String stuName) {
this.stuName = stuName;
}
public String getStuName() {
return stuName;
}
public void setStuName(String stuName) {
this.stuName = stuName;
}
@Override
public String toString() {
return "Student{" +
"stuName='" + stuName + '\'' +
'}';
}
}
测试类
package com.cmy.streamdemo;
import java.util.ArrayList;
import java.util.stream.Stream;
/**
* @author chenmingyong
*/
public class Practice {
public static void main(String[] args) {
// 创建存储男同学的姓名集合
ArrayList<String> maleList = new ArrayList<>();
maleList.add("轩辕浅");
maleList.add("百里回");
maleList.add("百殇");
maleList.add("慕容凰");
maleList.add("洋希");
maleList.add("诸葛尘");
// 创建存储女同学的姓名集合
ArrayList<String> femaleList = new ArrayList<>();
femaleList.add("李疏寒");
femaleList.add("凌雪姣");
femaleList.add("江舞寒");
femaleList.add("李梦儿");
femaleList.add("李楠楠");
femaleList.add("李锦");
// 筛选男同学,只要名字为3个字的前三个人
Stream<String> maleStream = maleList.stream().filter(male -> male.length() == 3).limit(3);
// 筛选女同学,只要姓李的,并且跳过第一个人
Stream<String> femaleStream = femaleList.stream().filter(female -> female.startsWith("李")).skip(1);
// 合并两个流并将得到的元素作为构造方法的参数创建学生对象,然后遍历数据
Stream.concat(maleStream, femaleStream).forEach(s -> {
Student student = new Student(s);
System.out.println(student);
});
}
}