流的分类
Stream
stream 是串行的,通俗来讲就是按顺序执行
parallelStream
parallelStream 是并行的,采用分治的原理实现,先将流拆分,处理完之后再合并处理结果,执行具有不要确定性,不推荐在不适用的场景下使用
常用流的创建
- Collection的stream()方法
- Stream.of()等流的静态方法
- Arrays.stream()方法
流的中间操作
相关示例类如下
- Student
public class Student {
private String name; // 姓名
private String gender; // 性别
private Integer grade; // 成绩
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", gender='" + gender + '\'' +
", grade=" + grade +
'}';
}
public Student() {
}
public Student(String name, String gender, Integer grade) {
this.name = name;
this.gender = gender;
this.grade = grade;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getGender() {
return gender;
}
public void setGender(String gender) {
this.gender = gender;
}
public Integer getGrade() {
return grade;
}
public void setGrade(Integer grade) {
this.grade = grade;
}
}
- People
public class People {
private String name; // 姓名
private String gender; // 性别
@Override
public String toString() {
return "People{" +
"name='" + name + '\'' +
", gender='" + gender + '\'' +
'}';
}
public People() {
}
public People(String name, String gender) {
this.name = name;
this.gender = gender;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getGender() {
return gender;
}
public void setGender(String gender) {
this.gender = gender;
}
}
- 添加数据
ArrayList<Student> list = new ArrayList<>();
// 男生
Student student1 = new Student("张三", "男", 60);
Student student2 = new Student("李四", "男", 70);
Student student3 = new Student("王五", "男", 80);
Student student4 = new Student("赵六", "男", 90);
Student student5 = new Student("钱七", "男", 100);
// 女生
Student student6 = new Student("西施", "女", 100);
Student student7 = new Student("貂蝉", "女", 100);
Student student8 = new Student("王昭君", "女", 100);
Student student9 = new Student("李飞燕", "女", 100);
list.add(student1);
list.add(student2);
list.add(student3);
list.add(student4);
list.add(student5);
list.add(student6);
list.add(student7);
list.add(student8);
list.add(student9);
map
map 常用来将一个流映射为另外一个流(需要传入的参数就是映射的规则)
- 例子1:将所有学生的姓名拿出来组成一个新的集合
List<String> studentNames = list.stream().map(Student::getName).collect(Collectors.toList());
System.out.println(studentNames);
// 输出结果
// [张三, 李四, 王五, 赵六, 钱七, 西施, 貂蝉, 王昭君, 李飞燕]
- 例子2:将学生映射成为人
List<People> peopleList = list.stream().map(e -> new People(e.getName(), e.getGender())).collect(Collectors.toList());
for (People people : peopleList) {
System.out.println(people);
}
// 输出结果
// People{name='张三', gender='男'}
// People{name='李四', gender='男'}
// People{name='王五', gender='男'}
// People{name='赵六', gender='男'}
// People{name='钱七', gender='男'}
// People{name='西施', gender='女'}
// People{name='貂蝉', gender='女'}
// People{name='王昭君', gender='女'}
// People{name='李飞燕', gender='女'}
filter
filter 常用来过滤数据 (传入的参数就是过滤的规则)
- 例子1 :过滤出所有的女生
List<Student> students = list.stream().filter(e -> "女".equals(e.getGender())).collect(Collectors.toList());
for (Student student : students) {
System.out.println(student);
}
// 输出结果
// Student{name='西施', gender='女', grade=100}
// Student{name='貂蝉', gender='女', grade=100}
// Student{name='王昭君', gender='女', grade=100}
// Student{name='李飞燕', gender='女', grade=100}
limit
limit 一般用于截断操作 (传入的参数为截取几个)
- 例子1:取出前3个
List<Student> students = list.stream().limit(3).collect(Collectors.toList());
for (Student student : students) {
System.out.println(student);
}
// 输出结果
// Student{name='张三', gender='男', grade=60}
// Student{name='李四', gender='男', grade=70}
// Student{name='王五', gender='男', grade=80}
skip
skip 对流进行跳过操作 (传入的参数为跳过前几个)
- 例子:跳过前三个
List<Student> students = list.stream().skip(3).collect(Collectors.toList());
for (Student student : students) {
System.out.println(student);
}
// 输出结果
// Student{name='赵六', gender='男', grade=90}
// Student{name='钱七', gender='男', grade=100}
// Student{name='西施', gender='女', grade=100}
// Student{name='貂蝉', gender='女', grade=100}
// Student{name='王昭君', gender='女', grade=100}
// Student{name='李飞燕', gender='女', grade=100}
distinct
distinct 进行去重操作 (传入的参数为去重的规则)
- 例子:
List<Integer> collect = Stream.of(1, 2, 3, 1, 2, 3).distinct().collect(Collectors.toList());
for (Integer integer : collect) {
System.out.println(integer);
}
// 输出结果
// 1
// 2
// 3
peek
peek 生成一个包含原Stream的所有元素的新Stream,同时会提供一个消费函数(Consumer实例),新Stream每个元素被消费的时候都会执行给定的消费函数,peek主要被用在debug用途
- 例子
Stream.of("one", "two", "three","four").filter(e -> e.length() > 3)
.peek(e -> System.out.println("Filtered value: " + e))
.map(String::toUpperCase)
.peek(e -> System.out.println("Mapped value: " + e))
.collect(Collectors.toList());
// 输出
// Filtered value: three
// Mapped value: THREE
// Filtered value: four
// Mapped value: FOUR
sorted
sorted 常用来对流进行排序操作
- 例子:对学生按照成绩进行倒序排序
List<Student> students = list.stream().sorted(Comparator.comparingInt(Student::getGrade).reversed()).collect(Collectors.toList());
for (Student student : students) {
System.out.println(student);
}
// 输出结果
// Student{name='钱七', gender='男', grade=100}
// Student{name='西施', gender='女', grade=100}
// Student{name='貂蝉', gender='女', grade=100}
// Student{name='王昭君', gender='女', grade=100}
// Student{name='李飞燕', gender='女', grade=100}
// Student{name='赵六', gender='男', grade=90}
// Student{name='王五', gender='男', grade=80}
// Student{name='李四', gender='男', grade=70}
// Student{name='张三', gender='男', grade=60}
流的终止操作
collect
转换成list Collectors.toList
List<Student> students = list.stream().filter(e -> "女".equals(e.getGender())).collect(Collectors.toList());
转换成具体的类型 Collectors.toCollection
list.stream().filter(e -> "女".equals(e.getGender())).collect(Collectors.toCollection(ArrayList::new));
list.stream().filter(e -> "女".equals(e.getGender())).collect(Collectors.toCollection(HashSet::new));
拼接字符串 Collectors.joining
Stream<String> stream = Stream.of("hello", "world", "helloworld");
String s = stream.collect(Collectors.joining(","));
System.out.println(s);
// 输出
// hello,world,helloworld
映射 Collectors.mapping
list.stream().collect(Collectors.mapping(Student::getName, Collectors.joining("、")));
比较取小 Collectors.minBy
list.stream().collect(Collectors.minBy(Comparator.comparingInt(Student::getGrade))).get();
list.stream().min(Comparator.comparingInt(Student::getGrade)).get();
比较取大 Collectors.maxBy
list.stream().collect(Collectors.maxBy(Comparator.comparingInt(Student::getGrade))).get();
list.stream().max(Comparator.comparingInt(Student::getGrade)).get();
求和
list.stream().collect(Collectors.summarizingInt(Student::getGrade)).getSum();
求平均值
list.stream().collect(Collectors.summarizingInt(Student::getGrade)).getAverage();
分组后按照map展示
Map<String, List<Student>> collect = list.stream().collect(Collectors.groupingBy(Student::getGender));
分组计数
list.stream().collect(Collectors.groupingBy(Student::getGender, Collectors.counting()));
分组求和
list.stream().collect(Collectors.groupingBy(Student::getGender, Collectors.summingInt(Student::getGrade)));
分组求平均
list.stream().collect(Collectors.groupingBy(Student::getGender, Collectors.averagingInt(Student::getGrade)));
分组后取最大
list.stream().collect(Collectors.groupingBy(Student::getGender, Collectors.maxBy(Comparator.comparingInt(Student::getGrade))));
分组后取最小
list.stream().collect(Collectors.groupingBy(Student::getGender, Collectors.minBy(Comparator.comparingInt(Student::getGrade))));
将结果转换成Map Collectors.toMap
可能会导致key重复的情况,需自行配置规则防止重复key报错。
Map<String, Student> collect = list.stream().collect(Collectors.toMap(Student::getName, v -> v, (o1, o2) -> o1));
forEach
迭代流中的每一个数据,等同于for循环
List<String> items = Arrays.asList("a","b","c","d","e");
items.forEach(item->System.out.println(item));
//输出 a,b,c,d,e
find
- findAny查找任何一个就返回 Optional
List<String> strings = Arrays.asList("abc", "dd", "DD", "dd", "abcd","cc", "jkl");
String result = strings.stream().filter(str -> str.equals("dd"))
.findAny()
.orElse(null);
System.out.println(result);
//输出 dd
- findFirst查找到第一个就返回 Optional
List<String> strings = Arrays.asList("abc", "dd", "DD", "dd", "abcd","cc", "jkl");
String result = strings.stream().filter(str -> str.equals("dd"))
.findFirst()
.orElse(null);
System.out.println(result);
//输出 dd
- anyMatch匹配上任何一个则返回Boolean
List<String> strings = Arrays.asList("abc", "dd", "DD", "dd", "abcd","cc", "jkl");
Boolean result = strings.stream().anyMatch(str -> str.equals("dd"));
System.out.println(result);
//输出 true
- allMatch匹配所有的元素则返回Boolean
List<String> strings = Arrays.asList("abc", "dd", "DD", "dd", "abcd","cc", "jkl");
Boolean result = strings.stream().allMatch(str -> str.equals("dd"));
System.out.println(result);
//输出 false
- noneMatch检查在所需位置是否没有带有必需字符的元素,返回Boolean
List<String> strings = Arrays.asList("abc", "dd", "DD", "dd", "abcd","cc", "jkl");
Boolean result = strings.stream().noneMatch(str -> str.equals("ff"));
System.out.println(result);
//输出 true
reduce
它可以把一个Stream的所有元素按照聚合函数聚合成一个结果
// 0代表初始值 如果不传0 则使用第一个元素作为初始值,acc是计算值,n 是每个元素
int sum = Stream.of(1, 2, 3, 4, 5, 6, 7, 8, 9).reduce(0, (acc, n) -> acc + n);
System.out.println(sum); // 45
//不传初始值的情况下,返回的是Optional类型的结果
List<Integer> numList = Arrays.asList(1,2,3,4,5);
Optional<Integer> result = numList.stream().reduce((a, b) -> a + b);
System.out.println(result.get());