java复习

Iterator和Enumeration的区别

我们通常用Iterator(迭代器)或者Enumeration(枚举器)去遍历集合, 那么这个类有何区别?

直接上源码:
package java.util
public interface Enmeration {
    boolean hasMoreElements();
    E nextElement();
}

package java.util
public interface Iterator {
    boolean hasNext();
    E next();
    void remove(); **//迭代器这里比枚举器多一个方法哦.**
}

迭代器和枚举器的区别

  1. 枚举器(Enumberation)只提供了两个接口方法, 意味着我们只能读取数据.
  2. 迭代器(Iterator)在枚举器基础了又提供了一个对数据删除的操作.
  3. Iterator支持'Fail-Fast机制', 而Enumeration不支持.
  4. 枚举遍历的效率比迭代器效率高.

fail-fast简介

fail-fast机制是java集合(Collection)中的一中错误机制, 当多个线程对同一个集合的内容进行操作时, 就可能产生fail-fast事件.
如:
当一个线程A通过iterator去遍历某集合的过程中, 若该集合的内容被其他线程改变了, 那么线程A访问集合时, 就会抛出ConcurrentModificationException异常,产生fail-fast事件.

简单点说:线程A遍历集合list的过程中, list的内容被另外一个线程所改变了.就会抛出ConcurrentModificationException异常,即产生fail-fast事件.

fail-fast解决办法

fail-fast机制,是一种错误检测机制, 它只能被用来检测错误, 以为JDK并不保证fail-fast机制一定会发生.

具体分析:
产生fail-fast事件,是通过抛出ConcurrentModificationException异常来触发的。
那么,ArrayList是如何抛出ConcurrentModificationException异常的呢?

我们知道,ConcurrentModificationException是在操作Iterator时抛出的异常。我们先看看
Iterator的源码。ArrayList的Iterator是在父类AbstractList.java中实现的。代码如下:

package java.util;

public abstract class AbstractList extends AbstractCollection implements List {

    ...

    // AbstractList中唯一的属性
    // 用来记录List修改的次数:每修改一次(添加/删除等操作),将modCount+1
    protected transient int modCount = 0;

    // 返回List对应迭代器。实际上,是返回Itr对象。
    public Iterator iterator() {
        return new Itr();
    }
     //在AbstractList类中找到了Itr类的具体实现,它是AbstractList的一个成员内部类,
    // Itr是Iterator(迭代器)的实现类
    private class Itr implements Iterator {
         //cursor:表示下一个要访问的元素的索引,从next()方法的具体实现就可看出
        int cursor = 0;
         //lastRet:表示上一个访问的元素的索引
        int lastRet = -1;
         //expectedModCount:表示对ArrayList修改次数的期望值,它的初始值为modCount。
        // 修改数的记录值。
        // 每次新建Itr()对象时,都会保存新建该对象时对应的modCount;
        // 以后每次遍历List中的元素的时候,都会比较expectedModCount和modCount是否相等;
        // 若不相等,则抛出ConcurrentModificationException异常,产生fail-fast事件。
        int expectedModCount = modCount;

        public boolean hasNext() {
            return cursor != size();
        }

        public E next() {
            // 获取下一个元素之前,都会判断“新建Itr对象时保存的modCount”和“当前的modCount”是否相等;
            // 若不相等,则抛出ConcurrentModificationException异常,产生fail-fast事件。
            checkForComodification();
            try {
                E next = get(cursor);
                lastRet = cursor++;
                return next;
            } catch (IndexOutOfBoundsException e) {
                checkForComodification();
                throw new NoSuchElementException();
            }
        }

        public void remove() {
            if (lastRet == -1)
                throw new IllegalStateException();
            checkForComodification();

            try {
                AbstractList.this.remove(lastRet);
                if (lastRet < cursor)
                    cursor--;
                lastRet = -1;
                expectedModCount = modCount;
            } catch (IndexOutOfBoundsException e) {
                throw new ConcurrentModificationException();
            }
        }

        final void checkForComodification() {
            if (modCount != expectedModCount)
                throw new ConcurrentModificationException();
        }
    }

    ...
}
    

从中,我们可以发现在调用 next() 和 remove()时,都会执行 checkForComodification()。若 “modCount 不等于 expectedModCount”,则抛出ConcurrentModificationException异常,产生fail-fast事件。

1. 在单线程下,细心的朋友可能发现在Itr类中也给出了一个remove()方法:

public void remove() {
    if (lastRet == -1)
    throw new IllegalStateException();
       checkForComodification();
 
    try {
    AbstractList.this.remove(lastRet);
    if (lastRet < cursor)
        cursor--;
    lastRet = -1;
    expectedModCount = modCount;
    } catch (IndexOutOfBoundsException e) {
    throw new ConcurrentModificationException();
    }
}

在这个方法中,删除元素实际上调用的就是list.remove()方法,但是它多了一个操作:

expectedModCount = modCount;
因此,在迭代器中如果要删除元素的话,需要调用Itr类的remove方法。

代码举例:

public class Test {
    public static void main(String[] args)  {
        ArrayList list = new ArrayList();
        list.add(2);
        Iterator iterator = list.iterator();
        while(iterator.hasNext()){
            Integer integer = iterator.next();
            if(integer==2)
                iterator.remove();   //注意这个地方
        }
    }
}

2. 如果在多线程编程下

  • 最好用java.util.concurrent包下的类去取代java.util包下的类.
  • 1)在使用iterator迭代的时候使用synchronized或者Lock进行同步;
  • 2)使用并发容器CopyOnWriteArrayList代替ArrayList和Vector。

数组和集合排序

public class Person implements Comparable{

    private String name;
    private int age;

    @Override
    public int compareTo(Person o) {
        if(o.age > this.age) return 1;
        return -1;
    }
}

public static void main(String[] args) {
    Person[] persons = new Person[10];
        for (int i = 0; i < 10; i++) {

            Person person = new Person("daejong", (new Random()).nextInt(30)+1);
            persons[i] = person;
        }
        //Person实现了Comparable的内部排序法.
        Arrays.sort(persons);
        
        //指定一个比较器, 很灵活的进行排序, 外部排序法
        Arrays.sort(persons, new Comparator() {
            @Override
            public int compare(Person o1, Person o2) {

                if(o1.getAge() > o2.getAge()) return 1;
                return -1;
            }
        });
}

集合Collections是专门处理容器的类,该类的Collections.sort()类似Arrays.sort()只是作用的
对象不一样而已.

/*
* Collections类似Arrays, 是对Collection类的一些类方法,HashMap, treeMap, HashSet, treeSet, ArrayList, LinkedList
* 附加注意:
*
Map.Entry
Iterator
Enumeration
HashMap: 最多允许一条记录的键为null, 允许多条记录的值为null.
Hashtable: 不允许键或值为空.
LinkedHashMap: 保存了插入的顺序.
TreeMap: 默认按照键升序排序.
*
Collections.sort(List list); //T中实现内部排序接口
Collections.sort(List Comparatorc); //执行一个比较器 进行排序.
* */

排序总结

/*
* Comparator和Comparable比较
1.Comparable是排序接口, 若一个类实现了Comparable接口, 就意味着该类支持排序. 要实现CompareTo(T o)方法
2.而Comparator是比较器, 我们如果需要控制某个类的次序, 可以创建一个该类的比较器来进行排序. 要实现Compare(T o1, T o2)方法.
3. 不难发现, Comparable相当于'内部比较器', Comparator相当于'外部比较器'.
* */

/*
* Arrays排序都是经过调优的快速排序
* 1. 对基本类型的数组进行排序, Arrays提供了默认的升序排序,没有提供相应的降序排序
* 2. 若要对基本数据类型进行降序排序, 需要将这些数组转化为对应的封装类数组. 如Integer[], Double[], Character[]
* */

你可能感兴趣的:(java复习)