Iterator
Java Iterator(迭代器)不是一个集合,它是一种用于访问集合的方法,可用于迭代 ArrayList 和 HashSet 等集合,foreach底层也是一个迭代器,集合的的删除操作要在迭代器中进行操作,拿ArrayList举例,底层是数组结构,在进行元素删除的时候,后边的元素要前移一位,这时候对应索引上的值发生了变化,如下,若在循环中进行删除操作之后,当前索引位置i上的值被删除,i+1索引位置上的值会自动移到i上,i+1的值变成i+2索引位置的值,在进行i+1索引位置的值删除的是原i+2的值,而原i+1位置上的值已经在原i位置上,可能造成漏删。
ArrayList<String> s = new ArrayList<>();
s.add("1");
s.add("2");
s.add("3");
s.add("4");
s.add("5");
System.out.println(s.get(2));//3
s.remove(2);
System.out.println(s.get(2));//4
迭代器 it 的两个基本操作是 next 、hasNext 和 remove。
ArrayList<Integer> numbers = new ArrayList<Integer>();
numbers.add(12);
numbers.add(8);
numbers.add(2);
numbers.add(23);
Iterator<Integer> it = numbers.iterator();
while(it.hasNext()) {
Integer i = it.next();
if(i < 10) { //次数的判断条件有时候可以结合stream流进行代替
it.remove(); // 删除小于 10 的元素
}
}
System.out.println(numbers);
}
迭代器的内部有两个计数的变量,初始位置是在-1位置开始的,一般是it.hasNext() ,有的话,it.next(),返回值是集合的一个元素,因为是从-1开始的所以集合的下一个索引位置上的元素是0索引位置的,然后it.remove(),删除当前满足条件的元素。
Stream
Stream相当于Iterator的高级使用,提供一个内部迭代方式
分为三部分:创建流,转换流,聚合
创建流的操作方式:
Collection接口提供了构建流的方法:stream() 方法
Stream接口的静态工厂方法
转换流
distinct:
对于Stream中包含的元素进行去重操作(去重逻辑依赖元素的equals方法),新生成的Stream中没有重复的元素
filter:
对于Stream中包含的元素使用给定的过滤函数进行过滤操作,新生成的Stream只包含符合条件的元素
map:
对于Stream中包含的元素使用给定的转换函数进行转换操作,新生成的Stream只包含转换生成的元素。
flatMap:
和map类似,不同的是其每个元素转换得到的是Stream对象,会把子Stream中的元素压缩到父集合中
peek:
生成一个包含原Stream的所有元素的新Stream,同时会提供一个消费函数(Consumer实例),新Stream每个元素被消费的时候都会执行给定的消费函数;
limit: 对一个Stream进行截断操作,获取其前N个元素,如果原Stream中包含的元素个数小于N,那就获取其所有的元素
skip: 返回一个丢弃原Stream的前N个元素后剩下元素组成的新Stream,如果原Stream中包含的元素个数小于N,那么返回空Stream
中间的转换流可以不断的组合
List<Integer> nums = Lists.newArrayList(1,1,null,2,3,4,null,5,6,7,8,9,10);
System.out.println(“sum is:”+nums.stream().filter(num -> num != null).
distinct().mapToInt(num -> num * 2).
peek(System.out::println).skip(2).limit(4).sum());
聚合
可变汇聚对应的只有一个方法:collect 将中间流的结果汇聚到一个容器里
Collector的工具类–[Collectors]:Collectors.toCollection()/Collectors.toList()/Collectors.toSet()
例如:collect(Collectors.toList());
其他汇聚 reduce方法:reduce方法非常的通用
ints.stream().reduce((sum, item) -> sum + item).get()
reduce方法接受一个函数,这个函数有两个参数,第一个参数是上次函数执行的返回值(也称为中间结果),第二个参数是stream中的元素,这个函数把这两个值相加,得到的和会被赋值给下次执行这个函数的第一个参数。
count方法:获取Stream中元素的个数
allMatch:是不是Stream中的所有元素都满足给定的匹配条件
anyMatch:Stream中是否存在任何一个元素满足匹配条件
noneMatch:是不是Stream中的所有元素都不满足给定的匹配条件
findFirst: 返回Stream中的第一个元素,如果Stream为空,返回空Optional
总结:
关于上述代码中说的Iterator和Stream结合使用的例子:
提供两个类:Student 和
@Data
@Getter
@Setter
public class Student {
private String stuName;
private int stuAge;
public Student(String stuName, int stuAge) {
this.stuName = stuName;
this.stuAge = stuAge;
}
public Student() {
}
}
----------------------------------------------------------
@Data
@Getter
@Setter
public class User {
private String name;
private int age;
private List<Student> stu; // 两个 类的关系
public User(String name, int age, List<Student> stu) {
this.name = name;
this.age = age;
this.stu = stu;
}
public User() {
}
}
Student stu1 = new Student("学生小刘", 22);
Student stu2 = new Student("学生小张", 23);
Student stu3 = new Student("学生小赵", 24);
Student stu4 = new Student("学生小钱", 24);
Student stu5 = new Student("学生小强", 24);
//模拟后端数据库查出来的数据(学生和用户存在关联关系)
ArrayList<Student> students = new ArrayList<>();
students.add(stu1);
students.add(stu2);
students.add(stu3);
students.add(stu4);
User user = new User("张三", 55, students);
//模拟前端传入的数据参数
ArrayList<Student> uStudents = new ArrayList<>();
uStudents.add(stu1);
uStudents.add(stu3);
uStudents.add(stu5);
User user2 = new User("赵六", 57, uStudents);
//假设后端采用的Spring Data 框架,继承了Hibenarate,实现更改集合元素可以自动更新中间表关系的
//换言之就是我想实现 模拟数据库查出来的数据 中和前端传入的数据比对,多余的就删除掉;前端传进来后端查出来的数据中没有的,就添加
//实现第一个需求:删除后端查出的数据中前端没传的
Iterator<Student> it = user.getStu().iterator();
while (it.hasNext()){
Student next = it.next();
if (user2.getStu().stream().noneMatch(item->next.getStuName().equals(item.getStuName()))) {
//此处就是stream流和Iterator的结合使用 作为删除的条件使用
it.remove();
}
}
System.out.println(user);
//User(name=张三, age=55, stu=[Student(stuName=学生小刘, stuAge=22), Student(stuName=学生小赵, stuAge=24)])
//原先的stu2和stu3都没了,删掉了
//实现第二个需求就是前端传了新的额元素去后端进行存储的
// (都没进行对象的判空,目前还没掌握什么时候用Optional进行判空操作)
for (Student student : user2.getStu()) {
Optional<Student> first = user.getStu().stream().filter(item -> student.getStuName().equals(item.getStuName())).findFirst();
if (first.isPresent()){
continue;
}
user.getStu().add(student);
}
System.out.println(user);
//User(name=张三, age=55, stu=[Student(stuName=学生小刘, stuAge=22), Student(stuName=学生小赵, stuAge=24), Student(stuName=学生小强, stuAge=24)])
//将前端新传入的后端没存入的参数添加到集合中,
xxxmethod.save(user) //重新保存并更新中间表关系
}