Java中ArrayList去重代码里size--的作用疑问
size--作用的解析 你提到这段去重代码只有加上size--才能正常运行,疑惑为什么for循环不会自动处理集合大小的变化,下面就拆解size--的核心作用:
首先看你的代码逻辑:
public static ArrayList<String> removeDuplicates(ArrayList<String> members) { int size = members.size(); for(int i = 0; i < size - 1; i++) { for(int j = i + 1; j < size; j++) { if(members.get(i).equals(members.get(j))) { members.remove(i); i--; size--; } } } return members; }
size--的核心作用
同步缓存值与集合真实大小
你一开始就把集合的初始大小存在了size变量里,后续循环的终止条件(i < size -1、j < size)都是基于这个缓存值,而不是每次调用members.size()获取实时大小。当执行members.remove(i)后,ArrayList的实际元素数量已经减1,但缓存的size不会自动更新,如果不手动size--,这个变量就和集合真实大小脱节,后续循环会访问超出集合范围的索引,直接抛出IndexOutOfBoundsException。控制循环的迭代范围
外层循环的终止条件是i < size -1,如果不更新size,当集合元素被删除后,i的上限还是初始的size-1,会导致i遍历到已经不存在的元素位置。比如初始集合大小是5,删除2个元素后实际大小是3,但外层循环还会让i跑到3(初始size-1是4),此时members.get(i)就会触发越界异常。避免无效的循环迭代
内层循环j的范围是j < size,如果size不更新,j会一直循环到初始的大小值,而那些超过当前集合真实大小的j值都是无效的,既浪费性能,又会引发异常。
补充说明
如果你把循环条件改成直接依赖members.size(),比如:
for(int i = 0; i < members.size() - 1; i++) { for(int j = i + 1; j < members.size(); j++) { // ... 逻辑不变 } }
那确实不需要手动维护size变量,因为每次循环都会获取集合的实时大小。但你的代码选择了提前缓存size的方式,就必须通过size--来同步这个变量和集合的真实状态,否则循环逻辑就会出错。
内容的提问来源于stack exchange,提问作者P M

