1. 容器类

Java容器类类库的用途是保存对象,并将其划分为两个不同的概念:

1) Collection: 一个独立元素的序列,这些元素都服从一条或多条规则。List必须按照插入的顺序保存元素,而Set不能有重复元素。Queue按照排队规则来确定对象产生的顺序。

2) Map: 一组成对的键值对对象,允许使用键来查找值。映射表允许使用另一个对象来查找某个对象,它也被称为关联数组,或者称为字典,Map是强大的编程工具。

在java.util包中的Arrays和Collections类中都有很多实用的方法,可以在一个Collection中添加一组元素。Arrays.asList()方法接受一个数组或是一个用逗号分隔的元素列表,并将其转换为一个List对象。Collections.addAll()方法接受一个Collections对象,以及一个数组或是一个用逗号分隔的列表,将元素添加到Collection中,例如:

Collection<Integer> collection = new ArrayList<Integer>(Arrays.asList(1, 2, 3));
Integer[] moreInts = {4, 5, 6};
collection.addAll(Arrays.asList(moreInts));
Collection.addAll(collection, 7, 8, 9);
Collection.addAll(collection, moreInts);


2. List

List可以将元素维护在特定的序列中,List接口在Collection的基础上添加了大量的方法,使得可以在List的中间插入和移除元素。有两种类型的List:基本的ArrayList,它优势在于随机访问元素,但是在中间插入和移除元素时较慢;LinkedList,它在List中间进行的插入和***操作代价较低,但在随机访问方面相对比较慢。

与数组不同,List允许在它被创建之后添加元素、移除元素,可以用contains()方法来确定某个对象是否在列表中,如果想移除一个对象,可以将这个对象的引用传递给remove()方法,同样,如果有一个对象的引用,则可以使用indexOf()来发现该对象在List中所处位置的索引编号,例如:

List<Pet> pets = Pets.arrayList(7);
pets.add(3, new Mouse());
Hamster h = new Hamster();
pets.add(h);
System.out.println(pets.contains(h));
pets.remove(h);
Pet p = pets.get(2);
pets.remove(p);
Pet cymric = new Cymric();
System.out.println(pets.indexOf(cymric));

subList()方法可以很容易地从较大的列表中创建出一个片断,如果将其结果传递给containsAll()方法必将得到true,retainAll()方法是一种有效的交集操作,它保留所有同时在两个片断中的元素,removeAll()方法将从List中移除在参数List中的所有元素,例如:

List<Pet> pets = Pets.arrayList(7);
List<Pet> sub = pets.subList(1, 4);
System.out.println(pets.containsAll(sub));
lIST<Pet> copy = new ArrayList<Pet>(pets);
copy.retainAll(sub);
copy = new ArrayList<Pet>(pets);
copy.set(1, new Mouse());
copy.addAll(2, sub);
copy.removeAll(sub);
copy.clear();


3. 迭代器

迭代器是一个对象,它的工作是遍历并选择序列中的对象,而客户端程序员不必知道或关心该序列底层的结构。此外,迭代器对象被称为轻量级对象,创建的代价较小,比如Java的Iterator只能单向移动,这个Iterator只能用来:

1) 使用方法iterator()要求容器返回一个Iterator,将准备好返回序列的第一个元素。

2) 使用next()获得序列中的下一个元素。

3) 使用hasNext()检查序列中是否还有元素。

4) 使用remove()将迭代器新近回的元素***。

例如:

List<Pet> pets = Pets.arrayList(10);
Iterator<Pet> it = pets.iterator();
while(it.hasNext) {
  Pet p = it.next();
  System.out.println(p.id());
}
for(Pet p : pets) {
  System.out.println(p.id());
}
it = pets.iterator();
for(int i = 0; i < 6;i ++) {
  it.next();
  it.remove();
}


4. Stack

栈通常是指后进先出的容器,有时栈也被称为叠加栈,因此最后入栈的元素,也是第一个出栈。LinkedList具有能够直接实现栈的所有功能的方法,因此可以直接将LinkedList作为栈使用,例如:

import java.util.LinkedList
public class Stack<T> {
  private LinkedList<T> storage = new LinkedList<T>();
  public void push(T v) {storage.addFirst(v);}
  public T peek() {return storage.getFirst();}
  public T pop() {return storage.removeFirst();}
  public boolean empty() {return storage.isEmpty();}
  public String toString() {return storage.toString();}
}


5. Set

Set不保存重复的元素,如果试图将相同对象的多个实例添加到Set中,那么它就会防止这种重复现象。Set具有与Collection完全一样的接口,因此没有任何额外的功能,实际上Set就是Collection,只是行为不同。查找是Set中最重要的操作,因此通常都会选择一个HashSet,它专门对快速查找进行了优化,例如:

Random rand = new Random(50);
Set<Integer> intset = new HashSet<Integer>();
for(int i = 0; i < 10000; i++) {
  intset.add(rand.nextInt(30));
}
System.out.println(intset);

如果想对结果排序,一种方式是使用TreeSet来代替HashSet,例如:

Random rand = new Random(50);
SortedSet<Integer> intset = new TreeSet<Integer>();
for(int i = 0; i < 10000; i++) {
  intset.add(rand.nextInt(30));
}
System.out.println(intset);


6. Map

将对象映射到其他对象的能力是一种解决编程问题的关键手段,比如一个程序用来检查Java的Random类的随机性,需要生成大量随机数,并对落入各种不同范围的数字进行计数,Map可以很容易解决该问题,例如:

Random rand = new Random(50);
Map<Integer.Integer> m = new HashMap<Integer.Integer>();
for(int i = 0; i < 10000; i++) {
  int r = rand.nextInt(20);
  Integer freq = m.get(r);
  m.put(r, freq == null ? 1 : freq + 1);
}
System.out.println(m);


7. Queue

队列是一个典型的先进先出的容器,即从容器的一端放入事物,从另一端取出,队列常被当作一种可靠的将对象从程序的某个区域传输到另一个区域的途径。LinkedList提供了方法以支持队列的行为,并且它实现了Queue接口,例如:

Queue<Integer> queue = new LinkedList<Integer>();
Random rand = new Random(50);
for (int i = 0; i < 10; i++) {
  queue.offer(rand.nextInt(i+10));
}
while(queue.peek() != null) {
  System.out.print(queue.remove() + " ");
}

offer()方法是与Queue相关的方法之一,它在允许的情况下,将一个元素插入到队尾,或者返回false,peek()和element()都将在不移除的情况下返回队头,但是peek()方法在队列为空时返回null,而element()会抛出异常。poll()和remove()方法将移除并返回队头,但是poll()在队列为空时返回null,而remove()会抛出异常。


8. foreach

foreach可以应用于任何Collection对象,例如:

Collection<String> cs = new LinkedList<String>();
Collection.addAll(cs, "Hello World !".split(" "));
for (String s : cs) {
  System.out.print("'" + s + "' ");
}

Java SE5引入了新的被称为Iterable的接口,该接口包含一个能够产生Iterator的iterator()方法,并且Iterable接口被foreach用来来序列中移动,因此如果创建了任何实现Iterable的类,都可以将它用于foreach语句中,例如:

public class IterableClass implements Iterable<String> {
  protected String[] words = "Hello World !".split(" ");
  public Iterator<String> iterator() {
    return new Iterator<String>() {
      private int index = 0;
      public boolean hasNext() {
        return index < words.length;
      }
      public String next() {
        return words[index++];
      }
      public void remove() {
        throw new UnsupportedOperationException();
      }
    }
  }
  public static void maint(String[] args) {
    for (String s : new IterableClass()) {
      System.out.print(s + " ");
    }
  }
}