A股上市公司传智教育(股票代码 003032)旗下技术交流社区北京昌平校区

 找回密码
 加入黑马

QQ登录

只需一步,快速开始

2. 迭代的效率较低

将一个集合(特别是由数组转化而成的集合)的内容转移到另一个集合,或者从一个较大对象集合中移除一个较小对象集合,这些事情并不鲜见。

您也许很想对集合进行迭代,然后添加元素或移除找到的元素,但是不要这样做。

在此情况下,迭代有很大的缺点:

每次添加或移除元素后重新调整集合将非常低效。
每次在获取锁、执行操作和释放锁的过程中,都存在潜在的并发困境。
当添加或移除元素时,存取集合的其他线程会引起竞争条件。
可以通过使用 addAll 或 removeAll,传入包含要对其添加或移除元素的集合作为参数,来避免所有这些问题。

3. 用 for 循环遍历任何 Iterable

Java 5 中加入 Java 语言的最大的便利功能之一,增强的 for 循环,消除了使用 Java 集合的最后一道障碍。

以前,开发人员必须手动获得一个 Iterator,使用 next() 获得 Iterator 指向的对象,并通过 hasNext() 检查是否还有更多可用对象。从 Java 5 开始,我们可以随意使用 for 循环的变种,它可以在幕后处理上述所有工作。

实际上,这个增强适用于实现 Iterable 接口的任何对象,而不仅仅是 Collections。

清单 2 显示通过 Iterator 提供 Person 对象的孩子列表的一种方法。 这里不是提供内部 List 的一个引用 (这使 Person 外的调用者可以为家庭增加孩子 — 而大多数父母并不希望如此),Person 类型实现 Iterable。这种方法还使得 for 循环可以遍历所有孩子。

清单 2. 增强的 for 循环:显示孩子
  1. [java] view plaincopyprint?
  2.                   
  3. // Person.java   
  4. import java.util.*;  
  5.   
  6. public class Person  
  7.     implements Iterable<Person>  
  8. {  
  9.     public Person(String fn, String ln, int a, Person... kids)  
  10.     {  
  11.         this.firstName = fn; this.lastName = ln; this.age = a;  
  12.         for (Person child : kids)  
  13.             children.add(child);  
  14.     }  
  15.     public String getFirstName() { return this.firstName; }  
  16.     public String getLastName() { return this.lastName; }  
  17.     public int getAge() { return this.age; }  
  18.       
  19.     public Iterator<Person> iterator() { return children.iterator(); }  
  20.       
  21.     public void setFirstName(String value) { this.firstName = value; }  
  22.     public void setLastName(String value) { this.lastName = value; }  
  23.     public void setAge(int value) { this.age = value; }  
  24.       
  25.     public String toString() {   
  26.         return "[Person: " +  
  27.             "firstName=" + firstName + " " +  
  28.             "lastName=" + lastName + " " +  
  29.             "age=" + age + "]";  
  30.     }  
  31.       
  32.     private String firstName;  
  33.     private String lastName;  
  34.     private int age;  
  35.     private List<Person> children = new ArrayList<Person>();  
  36. }  
  37.   
  38. // App.java   
  39. public class App  
  40. {  
  41.     public static void main(String[] args)  
  42.     {  
  43.         Person ted = new Person("Ted", "Neward", 39,  
  44.             new Person("Michael", "Neward", 16),  
  45.             new Person("Matthew", "Neward", 10));  
  46.   
  47.         // Iterate over the kids   
  48.         for (Person kid : ted)  
  49.         {  
  50.             System.out.println(kid.getFirstName());  
  51.         }  
  52.     }  
  53. }  
复制代码
在域建模的时候,使用 Iterable 有一些明显的缺陷,因为通过 iterator() 方法只能那么 “隐晦” 地支持一个那样的对象集合。但是,如果孩子集合比较明显,Iterable 可以使针对域类型的编程更容易,更直观。

4. 经典算法和定制算法

您是否曾想过以倒序遍历一个 Collection?对于这种情况,使用经典的 Java Collections 算法非常方便。

在上面的 清单 2 中,Person 的孩子是按照传入的顺序排列的;但是,现在要以相反的顺序列出他们。虽然可以编写另一个 for 循环,按相反顺序将每个对象插入到一个新的 ArrayList 中,但是 3、4 次重复这样做之后,就会觉得很麻烦。

在此情况下,清单 3 中的算法就有了用武之地:

清单 3. ReverseIterator
  1. [java] view plaincopyprint?
  2.                   
  3. public class ReverseIterator  
  4. {  
  5.     public static void main(String[] args)  
  6.     {  
  7.         Person ted = new Person("Ted", "Neward", 39,  
  8.             new Person("Michael", "Neward", 16),  
  9.             new Person("Matthew", "Neward", 10));  
  10.   
  11.         // Make a copy of the List   
  12.         List<Person> kids = new ArrayList<Person>(ted.getChildren());  
  13.         // Reverse it   
  14.         Collections.reverse(kids);  
  15.         // Display it   
  16.         System.out.println(kids);  
  17.     }  
  18. }  
复制代码
Collections 类有很多这样的 “算法”,它们被实现为静态方法,以 Collections 作为参数,提供独立于实现的针对整个集合的行为。

而且,由于很棒的 API 设计,我们不必完全受限于 Collections 类中提供的算法 — 例如,我喜欢不直接修改(传入的 Collection 的)内容的方法。所以,可以编写定制算法是一件很棒的事情,例如清单 4 就是一个这样的例子:

清单 4. ReverseIterator 使事情更简单
  1. [java] view plaincopyprint?
  2.                   
  3. class MyCollections  
  4. {  
  5.     public static <T> List<T> reverse(List<T> src)  
  6.     {  
  7.         List<T> results = new ArrayList<T>(src);  
  8.         Collections.reverse(results);  
  9.         return results;  
  10.     }  
  11. }  
复制代码
5. 扩展 Collections API

以上定制算法阐释了关于 Java Collections API 的一个最终观点:它总是适合加以扩展和修改,以满足开发人员的特定目的。

例如,假设您需要 Person 类中的孩子总是按年龄排序。虽然可以编写代码一遍又一遍地对孩子排序(也许是使用 Collections.sort方法),但是通过一个 Collection 类来自动排序要好得多。

实际上,您甚至可能不关心是否每次按固定的顺序将对象插入到 Collection 中(这正是 List 的基本原理)。您可能只是想让它们按一定的顺序排列。

java.util 中没有 Collection 类能满足这些需求,但是编写一个这样的类很简单。只需创建一个接口,用它描述 Collection 应该提供的抽象行为。对于 SortedCollection,它的作用完全是行为方面的。


清单 5. SortedCollection
  1. [java] view plaincopyprint?
  2.                   
  3. public interface SortedCollection<E> extends Collection<E>  
  4. {  
  5.     public Comparator<E> getComparator();  
  6.     public void setComparator(Comparator<E> comp);  
  7. }  
复制代码
[java] view plaincopyprint?
                  
public interface SortedCollection<E> extends Collection<E>  
{  
    public Comparator<E> getComparator();  
    public void setComparator(Comparator<E> comp);  
}
  1. [java] view plaincopyprint?
  2. import java.util.*;  
  3.   
  4. public class ArraySortedCollection<E>  
  5.     implements SortedCollection<E>, Iterable<E>  
  6. {  
  7.     private Comparator<E> comparator;  
  8.     private ArrayList<E> list;  
  9.          
  10.     public ArraySortedCollection(Comparator<E> c)  
  11.     {  
  12.         this.list = new ArrayList<E>();  
  13.         this.comparator = c;  
  14.     }  
  15.     public ArraySortedCollection(Collection<? extends E> src, Comparator<E> c)  
  16.     {  
  17.         this.list = new ArrayList<E>(src);  
  18.         this.comparator = c;  
  19.         sortThis();  
  20.     }  
  21.   
  22.     public Comparator<E> getComparator() { return comparator; }  
  23.     public void setComparator(Comparator<E> cmp) { comparator = cmp; sortThis(); }  
  24.       
  25.     public boolean add(E e)  
  26.     { boolean r = list.add(e); sortThis(); return r; }  
  27.     public boolean addAll(Collection<? extends E> ec)   
  28.     { boolean r = list.addAll(ec); sortThis(); return r; }  
  29.     public boolean remove(Object o)  
  30.     { boolean r = list.remove(o); sortThis(); return r; }  
  31.     public boolean removeAll(Collection<?> c)  
  32.     { boolean r = list.removeAll(c); sortThis(); return r; }  
  33.     public boolean retainAll(Collection<?> ec)  
  34.     { boolean r = list.retainAll(ec); sortThis(); return r; }  
  35.       
  36.     public void clear() { list.clear(); }  
  37.     public boolean contains(Object o) { return list.contains(o); }  
  38.     public boolean containsAll(Collection <?> c) { return list.containsAll(c); }  
  39.     public boolean isEmpty() { return list.isEmpty(); }  
  40.     public Iterator<E> iterator() { return list.iterator(); }  
  41.     public int size() { return list.size(); }  
  42.     public Object[] toArray() { return list.toArray(); }  
  43.     public <T> T[] toArray(T[] a) { return list.toArray(a); }  
  44.       
  45.     public boolean equals(Object o)  
  46.     {  
  47.         if (o == this)  
  48.             return true;  
  49.          
  50.         if (o instanceof ArraySortedCollection)  
  51.         {  
  52.             ArraySortedCollection<E> rhs = (ArraySortedCollection<E>)o;  
  53.             return this.list.equals(rhs.list);  
  54.         }  
  55.          
  56.         return false;  
  57.     }  
  58.     public int hashCode()  
  59.     {  
  60.         return list.hashCode();  
  61.     }  
  62.     public String toString()  
  63.     {  
  64.         return list.toString();  
  65.     }  
  66.       
  67.     private void sortThis()  
  68.     {  
  69.         Collections.sort(list, comparator);  
  70.     }  
  71. }  
复制代码
这个实现非常简陋,编写时并没有考虑优化,显然还需要进行重构。但关键是 Java Collections API 从来无意将与集合相关的任何东西定死。它总是需要扩展,同时也鼓励扩展。

当然,有些扩展比较复杂,例如 java.util.concurrent 中引入的扩展。但是另一些则非常简单,只需编写一个定制算法,或者已有Collection 类的简单的扩展。

扩展 Java Collections API 看上去很难,但是一旦开始着手,您会发现远不如想象的那样难。

0 个回复

您需要登录后才可以回帖 登录 | 加入黑马