文章目录
并发修改异常
ConcurrentModificationException 异常
- 软件包是java.util包
- 该异常类继承自RuntimeException异常
- 当不允许这样的修改时,可以通过检测到对象的并发修改的方法来抛出此异常
- 理解xhj:并发修改异常
并发修改异常:ConcurrentModificationException 发生问题的案例
// 29-ListDemo3
public class ListDemo3 {
//需求:
/*
有一个集合,
添加三个元素 hello、world、java,
遍历集合,得到每一个元素,看有没有world这个元素,如果有则添加元素javaee
* */
public static void main(String[] args){
List<String> list = new ArrayList<String>(); 分析步骤1
String s1 = "hello";
String s2 = "world";
String s3 = "java";
list.add(s1);
list.add(s2);
list.add(s3);
//采用for循环的形式遍历集合元素不报错
/* for (int i = 0 ; i <list.size() ; i++){
String s = list.get(i);
if(s.equals("world")){
list.add("javaee");
}
}*/
//采用迭代器的形式
Iterator<String> it = list.iterator(); 分析步骤1
while (it.hasNext()) {
String s = it.next();
if(s.equals("world")){
list.add("javaee"); 分析步骤1
}
}
// 使用迭代器遍历集合元素会报错:ConcurrentModificationException
System.out.println(list);
}
}
原因分析:采用迭代器出现异常
主要:采用迭代器的形式,对集合进行add添加元素操作之后,modCount变量的数值会增加,exceptedModCount变量不变,集合对象.next方法获取集合变量的时候会执行checkForComodification()方法,比较modCount和exceptedModCount的数值,不相等会报ConcurrentModificationException异常。
1 首先是List接口,接着使用接口中定义的两个方法:iterator、add
public interface List<E> {
Iterator<E> iterator();
boolean add(E e);
}
2 最终创建对象,new的是ArrayList这个实现类的对象
public abstract class AbstractList<E>{
protected transient int modCount = 0;
此变量在AbstractList<E>类中
}
public class ArrayList<E> extends AbstractList<E> implements List<E> {
ArrayList实现了List这个接口,就需要重写List中的方法,例如:iterator、add
public boolean add(E e) {
ensureCapacityInternal(size + 1); //自己测试显示内容
elementData[size++] = e;
return true;
//视频显示内容
modCount++;
add(e,elementData,size);
return true;
}
public Iterator<E> iterator() {
return new Itr();
}
private class Itr implements Iterator<E> {
int expectedModCount = modCount;
/*
expectedModCound:预期修改集合的次数
modCount:实际修改集合的次数
最开始执行时,两者数量相同
变量modCount来自AbstractList<E>中,且用protected修饰,则子类可以直接访问到父类的成员变量,所以最开始两个变量的值都是0
*/
/*
在实际代码运行中,
if(s.equals("world")){
list.add("javaee"); 分析步骤1
}
上述代码一旦条件满足,就会执行集合添加元素的操作,
按照视频内容理解:每执行一次add方法,modCount会自加一,但是expectedModCount变量不变,接着执行next方法就会执行checkForComodification方法判断两者不相同时就会抛出异常。
*/
public E next() {
checkForComodification();
int i = cursor;
if (i >= size)
throw new NoSuchElementException();
Object[] elementData = ArrayList.this.elementData;
if (i >= elementData.length)
throw new ConcurrentModificationException();
cursor = i + 1;
return (E) elementData[lastRet = i];
}
final void checkForComodification() {
if (modCount != expectedModCount)
// 此处出现问题的原因是 modCount = 修改集合的次数、expectedModCount = 预期修改集合的次数
throw new ConcurrentModificationException();
}
}
}
3 分析 抛出异常的原因是it.next()方法执行,又调取checkForComodification()方法出现问题。
原因分析:采用for循环遍历集合元素不报错分析
使用for循环遍历,获取元素使用的是集合对象.get方法。
public class ArrayList<E> extends AbstractList<E> implements List<E> {
public E get(int index) {
rangeCheck(index);
return elementData(index);
}
调用get方法并没有对modCount、exceptedModCount变量进行比较,即使更改了modCount变量的值,但是也不影响执行。
}
关于视频和自己练习中add方法不相同问题理解:
public class ArrayList<E> extends AbstractList<E> implements List<E> {
// ArrayList实现了List这个接口,就需要重写List中的方法,例如:iterator、add
//自己测试显示内容
public boolean add(E e) {
ensureCapacityInternal(size + 1);
elementData[size++] = e;
return true;
}
分析是否相同:主要通过追述方法具体实现
private void ensureCapacityInternal(int minCapacity) {
ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));
}
private void ensureExplicitCapacity(int minCapacity) {
modCount++;
别的没有看懂,但是有关于变量modCount的++
// overflow-conscious code
if (minCapacity - elementData.length > 0)
grow(minCapacity);
}
private static int calculateCapacity(Object[] elementData, int minCapacity) {
if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
return Math.max(DEFAULT_CAPACITY, minCapacity);
}
return minCapacity;
}
//视频显示内容
public boolean add(E e) {
modCount++;
add(e,elementData,size);
return true;
}
并发修改异常解决及分析总结
并发修改异常:ConcurrentModificationException
产生原因:迭代器遍历的过程中,通过集合对象修改集合中的元素,比如添加元素(对象.add),造成了迭代器获取元素中判断预期修改值和实际修改值不一致
解决方法:用for循环遍历,然后用集合对象做对应的操作(对象.get)
冒泡排序
排序
将一组数据按照固定的规则进行排序
冒泡排序
一种排序的方式,对要进行排序的数据中相邻的数据进行两两比较,将较大的数据放在后面,依次对所有数据进行操作,直至所有数据按要求完成排序。
原理
①如果有n个数据进行排序,总共需要比较n-1次
②每一次比较完毕,下一次的比较就会少一个数据参与
案例:
public class ArrayDemo {
public static void main(String[] args) {
// 定义一个数组
int[] arr = {24,69,80,57,13};
System.out.println("排序前:" + arrayToString(arr));
arrayToReversear(arr);
System.out.println("排序后:" + arrayToString(arr));
}
//把数组中的元素按照指定的规则组成一个字符串:[元素1,元素2,...,元素n]
public static String arrayToString(int[] arr){
StringBuilder sb = new StringBuilder();
sb.append("[");
for (int i = 0 ; i <arr.length ; i ++){
if(i == arr.length - 1){
sb.append(arr[i]);
}else{
sb.append(arr[i]).append(", ");
}
}
sb.append("]");
String s = sb.toString();
return s;
}
public static void arrayToReversear(int[] arr){
int tep = 0;
for (int i = 0 ; i < arr.length ; i++) {
for (int j = 0; j < (arr.length - i - 1); j++) {
if (arr[j] > arr[j + 1]) {
tep = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = tep;
}
}
}
}
}