java-集合3

java-集合3

浏览以下内容前,请点击并阅读 声明

Queue接口(队列)

   需要对一些列的元素进行处理前,我们可以把他们放到Queue对象中,除了继承Collection接口的方法外,队列还有一些插入,删除和检查操作,Queue接口定义如下:

public interface Queue<E> extends Collection<E> {
    E element();
    boolean offer(E e);
    E peek();
    E poll();
    E remove();
}

  所有的对列方法都包含由两种形式:(1)如果方法执行失败,则抛出异常(2)另外,如果执行失败,也可能返回一个特殊的值,可以是null 或者false,该接口通常的结构如下表所示:

操作类型 抛出异常 返回特殊值
插入 add(e) offer(e)
删除 remove() poll()
检查 element() peek()

  队列一般以先进先出(FIFO)的顺序排列其元素,无论以什么顺序排列元素,其remove或者是poll方法都会移除并返回其排在开头的元素,所有实现Queue接口的类都要指定排序方式,remove和poll方法的唯一区别就在于当队列中不再含有元素的时候,remove方法会抛出NoSuchElementException,而poll返回null。

  Queue接口的实现类可以限制元素的数量,比如在java.util.concurrent包中的Queue接口实现类就对元素的数量进行了限制,而java.util包中的Queue类则没有限制。

  从Collection接口中继承的add方法被调用过后会向队列中添加一个元素,如果超过了队列元素数量最大的限制,就会抛出异常,offer方法只在限制元素数量的对列中使用,如果添加元素失败,则返回false而不会抛出异常。

  element和peek方法都是返回队列中排在开头位置的元素,不会移除任何元素,element和peek的区别在于当队列中不再含有元素的时候,element方法会抛出NoSuchElementException,而peek返回null。

  队列的实现类一般不允许插入null元素,LinkedList是例外,由于历史原因,他可以插入null元素,但最好不要使用这一特性,因为poll和peek方法执行失败时返回null。

  队列一般不定义基于元素的equals方法和hashCode方法,而是继承的Object的基于统一性的方法。

Deque接口

   Deque的发音与deck相同,它是一个两头队列,是一个支持从两端插入和移除元素的线性集合。Deque相较于Stack和Queue是一个功能更为丰富的抽象数据类型,因为它同时实现了Stack和Queue的方法,实现Deque接口的预定义类有ArrayDeque和LinkedList,Deque接口可以同时用作后进先出(LIFO)的Stack对象和先进先出(FIFO)的Queue对象,Deque的方法可以分为三类。

插入方法

  addfirst方法和offerFirst方法将制定的元素插入Deque对象的最开始,而addLast和offerLast则将元素插入Deque对象的最后,当Deque的大小被限制时,Deque对象元素数量达到最大以后,使用addLast和addrFirst方法会抛出异常。 

删除方法

  removeFirst和pollFirst方法会移除Deque对象中的开始的元素,而removeLast和pollLast方法则会移除Deque对象中最后的元素,当Deque对象为空时,使用removeLast和removeFirst方法会抛出异常,而使用pollFirst和pollLast方法则会返回null。

检索元素

   getFirst和peekFirst方法将会返回Deque对象中最开始的元素,而getLast和peekLast方法则返回Deque对象中最后的元素,使用这些方法不会对Deque对象造成影响,当Deque对象为空是,使用getFirst和getLast方法会抛出异常,而使用peekFirst和peekLast方法则返回null。

以上三类方法总结如下表:

操作类型 首个元素(Deque对象的开始) 最后一个元素 (Deque对象的结尾)
插入 addFirst(e)
offerFirst(e)
addLast(e)
offerLast(e)
删除 removeFirst()
pollFirst()
removeLast()
pollLast()
检索 getFirst()
peekFirst()
getLast()
peekLast()

 除了上述的方法意外,Deque接口还定义了其他的方法,如removeFirstOccurence方法,作用是移除Deque对象中首次出现的指定对象,如果没有出现指定元素,则不会对该Deque对象产生影响,类似的还有removeLastOccurence等。

Map接口

  一个Map对象是一个包含键-值对应关系的对象。一个map对象不能包含重复的键,而每一个键只能对应最多一个值,Map接口包含了一些基本操作的方法(如put, get, remove, containsKey, containsValue, size, 和 empty),批量操作方法(如putAll和clear)和集合视图操作(如keySet,entrySet和values)。

  java平台含有三种通用的Map实现类,HashMap,TreeMap和LinkedHashMap,他们的性能和行为表现就如同Set和中的HashSet,TreeSet和LinkedHashSet三种实现类类似。

Map接口基本操作

  Map的基本操作方法(如put, get, remove, containsKey, containsValue, size, 和 empty)和Hashtable类中的方法是一样的。

  想Set和List接口一样,Map 接口加强了强化了equals和hashCode方法的要求,两个Map对象即使是不同的实现类型也能够进行等同性的比较,如果两个Map对象含有相同的键-值对应关系,则可视为相等。

  一般情况下,所有的Map实现类都会提供一个参数为Map类型的参数,就像Collection接口一样,这样所有实现Map接口的类的实例都可以作为该构造器的参数,如下所示:

//假设对象m的类型是Map接口的实现类
Map<K, V> copy = new HashMap<K, V>(m);

 Map接口的批量操作

   Map接口的批量操作比较容易理解,putAll操作就如同Collection的addAll方法的效果一样,能够将一个Map对象的所有键-值对应关系复制到另外一个Map对象,另外putAll还有一个巧妙的用处,就是能够利用一个Map对象改写另外一个Map对象的键-值关系,如下例所示:

//该方法提供一个默认的Map对象,和一个改写的Map对象
static <K, V> Map<K, V> newAttributeMap(Map<K, V>defaults, Map<K, V> overrides) {
    Map<K, V> result = new HashMap<K, V>(defaults);
//result中和overrides所共有的键-值关系将会被改写
    result.putAll(overrides);
    return result;
}

 集合视图

  以下三种集合视图方法能够把Map对象看做是一个集合对象 :

  1. keySet--由Map中的键对象组成的Set对象。
  2. values--由Map对象中的值对象组成的Collection对象,该Collection对象不是Set对象,因为可能由多个键对应同一个值。
  3. entrySet--由Map对象中所有的键-值映射组成的Set对象,Map接口提供了一个嵌套的Map.Entry接口,返回的Set类型是这个接口类型。

  这些集合视图是迭代整个Map对象的唯一方法,有人担心每次调用集合视图的方法,都会产生一个新的集合对象,从而降低性能,不必担心,因为每次调用集合视图方法都是返回的同一个对象,而没有创建新的对象,所有的java.util包中的Map实现都是采用这样的策略。对集合视图方法产生的集合对象进行增删操作也会影响到后台的Map对象,如果该Map对象支持增删操作的话。

  Map.Entry中有一个setValue方法,如果Map对象支持值的更改的话,能够在迭代过程中更改值,注意这是在迭代过程中更改Map对象中值的唯一安全的方法,采用其他方法更改值会有不明确的后果。

  集合视图支持以任何形式移除元素,如remove,removeAll,retainAll和clear,还有Iterator.remove(Map需要支持移除元素)。然而集合视图不支持任何形式的元素增加。

  获得了集合视图以后,集合的批量操作方法(removeAll,retainAll,containAll)便也可以使用,首先如果你想判断两个Map对象是否为包含关系时,可用如下代码实现

//判断m1是否包含m2
m1.entrySet().containsAll(m2.entrySet())
//判断m1和m2是否含有相同的键
m1.keySet().equals(m2.keySet())

一对多映射

 Map中的键-值关系都是一个键只能对应一个值,然而还有一种情况是一个键对应多个值,然而这种情况并不多件,所以java集合框架内并没有包含这种映射。然而实现这种映射比较简单,就是将一个Map对象的值设为一个List对象就可以了。