什么是 Stream?
Stream(流)是一个来自数据源的元素队列并支持聚合操作元素是特定类型的对象,形成一个队列。 Java中的Stream并不会存储元素,而是按需计算。
数据源 流的来源。 可以是集合,数组,I/O channel, 产生器generator 等。
聚合操作 类似SQL语句一样的操作, 比如filter, map, reduce, find, match, sorted等。
和以前的Collection操作不同, Stream操作还有两个基础的特征:Pipelining: 中间操作都会返回流对象本身。 这样多个操作可以串联成一个管道, 如同流式风格(fluent >style)。 这样做可以对操作进行优化, 比如延迟执行(laziness)和短路( short-circuiting)。
内部迭代: 以前对集合遍历都是通过Iterator或者For-Each的方式, 显式的在集合外部进行迭代, 这叫做
外部迭代。 Stream提供了内部迭代的方式, 通过访问者模式(Visitor)实现。
一、逻辑运算
首先以下创建以学生为主的演示实体类,字段分别为姓名、年龄、性别、班级、成绩。
@Data
class Student {
private String name;
private int age;
// 性别
private String sex;
// 班级
private String grade;
// 成绩
private Double score;
public Student(String name, int age, String sex, String grade, Double score) {
this.name = name;
this.age = age;
this.sex = sex;
this.grade = grade;
this.score = score;
}
}
list 样例
public static void main(String[] args) {
List<Student> students = new ArrayList<Student>(){
{
add(new Student("张三",12,"男","一班",98.5));
add(new Student("李四",13,"女","二班",98.5));
add(new Student("王五",11,"男","二班",98.5));
add(new Student("赵六",13,"男","一班",98.5));
add(new Student("小红",11,"女","一班",98.5));
}
};
}
1. 使用stream 求和、最大、最小、平均值
(1)求和:
// 统计所有人的年龄
int sum = students.stream().mapToInt(Student::getAge).sum();
int sum1 = students.stream().mapToInt(s -> s.getAge()).sum();
(2)最大值:
students.stream().mapToInt(s -> s.getAge()).max();
(3)最小值:
students.stream().mapToInt(s -> s.getAge()).min();
(4)平均值:
students.stream().mapToInt(s -> s.getAge()).average();
当然还有 mapToInt(),还有mapToLong()、mapToDouble()等方法。
二、forEach
students.forEach(
student -> {
student.getAge();
}
);
三、分组操作
1.单个条件分组
Map<String, List<Student>> collect = students.stream().collect(Collectors.groupingBy(s -> s.getSex()));
2. 多个条件分组
Map<List<String>, List<Student>> collect1 = students.stream().collect(Collectors.groupingBy(s -> Arrays.asList(s.getSex(), s.getGrade())));
3. 将其中某两个字段转换成Map
Map<String, Integer> collect2 = students.stream().collect(Collectors.toMap(Student::getName, Student::getAge));
4.对重复键处理
- 在使用 Collectors.toMap 从流中创建 Map 时,如果存在重复的键,默认情况下会抛出 java.lang.IllegalStateException 异常。这是因为默认的合并函数无法处理重复键。
- 为了处理重复键的情况,你可以提供一个合并函数给 toMap 收集器,指定在遇到重复键时如何处理。例如,你可能希望在遇到重复键时对值进行求和,选择第一个值或选择最后一个值。
- 下面是如何处理重复键的具体示例:
(1)对重复键的值进行求和
Map<Integer, Integer> tsMap = tsList.stream()
.collect(Collectors.toMap(
ts -> Integer.valueOf(ts.get(“ysfs”).toString()),
ts -> Integer.valueOf(ts.get(“jsgs”).toString()),
(existingValue, newValue) -> existingValue + newValue
));
(2) 保留第一个遇到的值
Map<Integer, Integer> tsMap = tsList.stream()
.collect(Collectors.toMap(
ts -> Integer.valueOf(ts.get(“ysfs”).toString()),
ts -> Integer.valueOf(ts.get(“jsgs”).toString()),
(existingValue, newValue) -> existingValue
));
(3) 保留最后一个遇到的值
Map<Integer, Integer> tsMap = tsList.stream()
.collect(Collectors.toMap(
ts -> Integer.valueOf(ts.get(“ysfs”).toString()),
ts -> Integer.valueOf(ts.get(“jsgs”).toString()),
(existingValue, newValue) -> newValue
));
四、统计
1.将list 中的某个字段统计到list 中
List<String> nameList = students.stream().collect().map(Student::getName).collect(Collectors.toList());
评论区