关于Java您不知道的5件事(3)

2019-03-29 08:10

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 循环:显示孩子 // Person.java import java.util.*;

public class Person implements Iterable{

public Person(String fn, String ln, int a, Person... kids){ this.firstName = fn;

this.lastName = ln; this.age = a;

for (Person child : kids) children.add(child); }

public String getFirstName() { return this.firstName; } public String getLastName() { return this.lastName; } public int getAge() { return this.age; }

public Iterator iterator() { return children.iterator(); }

public void setFirstName(String value) { this.firstName = value; }

public void setLastName(String value) { this.lastName = value; } public void setAge(int value) { this.age = value; }

public String toString() { return \

\ \ \ }

private String firstName; private String lastName; private int age;

private List children = new ArrayList(); }

// App.java public class App{

public static void main(String[] args) {

Person ted = new Person(\ new Person(\), new Person(\

// Iterate over the kids for (Person kid : ted) {

System.out.println(kid.getFirstName()); } } }

在域建模的时候,使用 Iterable 有一些明显的缺陷,因为通过 iterator() 方法只能那么 “隐晦” 地支持一个那样的对象集合。但是,如果孩子集合比较明显,Iterable 可以使针对域类型的编程更容易,更直观。

4. 经典算法和定制算法

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

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

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

清单 3. ReverseIterator public class ReverseIterator{

public static void main(String[] args) { Person ted = new Person(\ new Person(\), new Person(\

// Make a copy of the List

List kids = new ArrayList(ted.getChildren()); // Reverse it

Collections.reverse(kids); // Display it

System.out.println(kids); } }

Collections 类有很多这样的 “算法”,它们被实现为静态方法,以 Collections 作为参数,提供独立于实现的针对整个集合的行为。

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

清单 4. ReverseIterator 使事情更简单 class MyCollections{

public static List reverse(List src) { List results = new ArrayList(src); Collections.reverse(results); return results; } }

5. 扩展 Collections API

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

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

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

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

清单 5. SortedCollection

public interface SortedCollection extends Collection{ public Comparator getComparator();

public void setComparator(Comparator comp);

}

编写这个新接口的实现简直不值一提:

清单 6. ArraySortedCollection import java.util.*;

public class ArraySortedCollection implements SortedCollection, Iterable{ private Comparator comparator; private ArrayList list;

public ArraySortedCollection(Comparator c) { this.list = new ArrayList(); this.comparator = c; }

public ArraySortedCollection(Collection src, Comparator c) { this.list = new ArrayList(src); this.comparator = c; sortThis(); }

public Comparator getComparator() { return comparator; }

public void setComparator(Comparator cmp) { comparator = cmp; sortThis(); }

public boolean add(E e) { boolean r = list.add(e); sortThis(); return r; }

public boolean addAll(Collection ec) { boolean r = list.addAll(ec); sortThis(); return r; } public boolean remove(Object o) { boolean r = list.remove(o); sortThis(); return r; }

public boolean removeAll(Collection c) { boolean r = list.removeAll(c); sortThis(); return r; } public boolean retainAll(Collection ec) { boolean r = list.retainAll(ec); sortThis(); return r; }

public void clear() { list.clear(); }

public boolean contains(Object o) { return list.contains(o); }

public boolean containsAll(Collection c) { return list.containsAll(c); } public boolean isEmpty() { return list.isEmpty(); } public Iterator iterator() { return list.iterator(); } public int size() { return list.size(); }

public Object[] toArray() { return list.toArray(); } public T[] toArray(T[] a) { return list.toArray(a); }

public boolean equals(Object o) { if (o == this)

return true;

if (o instanceof ArraySortedCollection) {

ArraySortedCollection rhs = (ArraySortedCollection)o; return this.list.equals(rhs.list);

} return false; }

public int hashCode() { return list.hashCode(); } public String toString() { return list.toString(); }

private void sortThis() { Collections.sort(list, comparator); } }

这个实现非常简陋,编写时并没有考虑优化,显然还需要进行重构。但关键是 Java Collections API 从来无意将与集合相关的任何东西定死。它总是需要扩展,同时也鼓励扩展。

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

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

结束语

和 Java Serialization 一样,Java Collections API 还有很多角落等待有人去探索 —正因为如此,我们还不准备结束这个话题。在 5 件事 系列 的下一篇文章中,将可以看到用 Java Collections API 做更多事情的 5 种新的方式。

参考资料

学习 ? 绍。 ? ? ? 档。 ? 讨论 ?

加入 My developerWorks 社区。

developerWorks Java 技术专区: 这里有数百篇关于 Java 编程每个方面的文章。

“Java 理论与实践: 并发集合类”(Brian Goetz,developerWorks,2003 年 7 月):学习 Doug Lea “使用泛型和并发改善集合”(John Zukowski,developerWorks,2008 年 4 月):介绍 Java 6 中 Java Collections Framework:阅读 Sun Microsystems 的 Java Collections Framework 和 API 文的 util.concurrent 包如何为标准集合类型 List 和 Map 注入新的活力。 Java Collections Framework 的变化。

“Introduction to the Collections Framework”(MageLang Institute, Sun Developer Network, 1999):这篇教程是很早以前的,但是很棒,它对并发集合之前的 Java Collections Framework 做了完整的介


关于Java您不知道的5件事(3).doc 将本文的Word文档下载到电脑 下载失败或者文档不完整,请联系客服人员解决!

下一篇:《诗经》两首练习及答案详解

相关阅读
本类排行
× 注册会员免费下载(下载后可以自由复制和排版)

马上注册会员

注:下载文档有可能“只有目录或者内容不全”等情况,请下载之前注意辨别,如果您已付费且无法下载或内容有问题,请联系我们协助你处理。
微信: QQ: