国产一级a片免费看高清,亚洲熟女中文字幕在线视频,黄三级高清在线播放,免费黄色视频在线看

打開APP
userphoto
未登錄

開通VIP,暢享免費電子書等14項超值服

開通VIP
關(guān)于 Java Collections API 您不知道的 5 件事,第 1 部分

對于很多 Java 開發(fā)人員來說,Java Collections API 是標準 Java 數(shù)組及其所有缺點的一個非常需要的替代品。將 Collections 主要與 ArrayList 聯(lián)系到一起本身沒有錯,但是對于那些有探索精神的人來說,這只是 Collections 的冰山一角。

關(guān)于本系列

您覺得自己懂 Java 編程?事實上,大多數(shù)程序員對于 Java 平臺都是淺嘗則止,只學(xué)習(xí)了足以完成手頭上任務(wù)的知識而已。在本 系列 中,Ted Neward 深入挖掘 Java 平臺的核心功能,揭示一些鮮為人知的事實,幫助您解決最棘手的編程挑戰(zhàn)。

雖然 Map(以及它的常用實現(xiàn) HashMap)非常適合名-值對或鍵-值對,但是沒有理由讓自己局限于這些熟悉的工具??梢允褂眠m當?shù)?API,甚至適當?shù)?Collection 來修正很多易錯的代碼。

本文是 5 件事 系列 中的第二篇文章,也是專門討論 Collections 的 7 篇文章中的第一篇文章,之所以花這么大的篇幅討論 Collections,是因為這些集合在 Java 編程中是如此重要。首先我將討論做每件事的最快(但也許不是最常見)的方式,例如將 Array 中的內(nèi)容轉(zhuǎn)移到 List。然后我們深入探討一些較少人知道的東西,例如編寫定制的 Collections 類和擴展 Java Collections API。

1. Collections 比數(shù)組好

剛接觸 Java 技術(shù)的開發(fā)人員可能不知道,Java 語言最初包括數(shù)組,是為了應(yīng)對上世紀 90 年代初期 C++ 開發(fā)人員對于性能方面的批評。從那時到現(xiàn)在,我們已經(jīng)走過一段很長的路,如今,與 Java Collections 庫相比,數(shù)組不再有性能優(yōu)勢。

例如,若要將數(shù)組的內(nèi)容轉(zhuǎn)儲到一個字符串,需要迭代整個數(shù)組,然后將內(nèi)容連接成一個 String;而 Collections 的實現(xiàn)都有一個可用的 toString() 實現(xiàn)。

除少數(shù)情況外,好的做法是盡快將遇到的任何數(shù)組轉(zhuǎn)換成集合。于是問題來了,完成這種轉(zhuǎn)換的最容易的方式是什么?事實證明,Java Collections API 使這種轉(zhuǎn)換變得容易,如清單 1 所示:


清單 1. ArrayToList
import java.util.*;
            public class ArrayToList
            {
            public static void main(String[] args)
            {
            // This gives us nothing good
            System.out.println(args);
            // Convert args to a List of String
            List<String> argList = Arrays.asList(args);
            // Print them out
            System.out.println(argList);
            }
            }

注意,返回的 List 是不可修改的,所以如果嘗試向其中添加新元素將拋出一個 UnsupportedOperationException

而且,由于 Arrays.asList() 使用 varargs 參數(shù)表示添加到 List 的元素,所以還可以使用它輕松地用以 new 新建的對象創(chuàng)建 List。


2. 迭代的效率較低

將一個集合(特別是由數(shù)組轉(zhuǎn)化而成的集合)的內(nèi)容轉(zhuǎn)移到另一個集合,或者從一個較大對象集合中移除一個較小對象集合,這些事情并不鮮見。

您也許很想對集合進行迭代,然后添加元素或移除找到的元素,但是不要這樣做。

在此情況下,迭代有很大的缺點:

  • 每次添加或移除元素后重新調(diào)整集合將非常低效。
  • 每次在獲取鎖、執(zhí)行操作和釋放鎖的過程中,都存在潛在的并發(fā)困境。
  • 當添加或移除元素時,存取集合的其他線程會引起競爭條件。

可以通過使用 addAllremoveAll,傳入包含要對其添加或移除元素的集合作為參數(shù),來避免所有這些問題。


3. 用 for 循環(huán)遍歷任何 Iterable

Java 5 中加入 Java 語言的最大的便利功能之一,增強的 for 循環(huán),消除了使用 Java 集合的最后一道障礙。

以前,開發(fā)人員必須手動獲得一個 Iterator,使用 next() 獲得 Iterator 指向的對象,并通過 hasNext() 檢查是否還有更多可用對象。從 Java 5 開始,我們可以隨意使用 for 循環(huán)的變種,它可以在幕后處理上述所有工作。

實際上,這個增強適用于實現(xiàn) Iterable 接口的任何對象,而不僅僅是 Collections。

清單 2 顯示通過 Iterator 提供 Person 對象的孩子列表的一種方法。 這里不是提供內(nèi)部 List 的一個引用 (這使 Person 外的調(diào)用者可以為家庭增加孩子 — 而大多數(shù)父母并不希望如此),Person 類型實現(xiàn) Iterable。這種方法還使得 for 循環(huán)可以遍歷所有孩子。


清單 2. 增強的 for 循環(huán):顯示孩子
// Person.java
            import java.util.*;
            public class Person
            implements Iterable<Person>
            {
            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<Person> 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 "[Person: " +
            "firstName=" + firstName + " " +
            "lastName=" + lastName + " " +
            "age=" + age + "]";
            }
            private String firstName;
            private String lastName;
            private int age;
            private List<Person> children = new ArrayList<Person>();
            }
            // App.java
            public class App
            {
            public static void main(String[] args)
            {
            Person ted = new Person("Ted", "Neward", 39,
            new Person("Michael", "Neward", 16),
            new Person("Matthew", "Neward", 10));
            // Iterate over the kids
            for (Person kid : ted)
            {
            System.out.println(kid.getFirstName());
            }
            }
            }
            

在域建模的時候,使用 Iterable 有一些明顯的缺陷,因為通過 iterator() 方法只能那么 “隱晦” 地支持一個那樣的對象集合。但是,如果孩子集合比較明顯,Iterable 可以使針對域類型的編程更容易,更直觀。


4. 經(jīng)典算法和定制算法

您是否曾想過以倒序遍歷一個 Collection?對于這種情況,使用經(jīng)典的 Java Collections 算法非常方便。

在上面的 清單 2 中,Person 的孩子是按照傳入的順序排列的;但是,現(xiàn)在要以相反的順序列出他們。雖然可以編寫另一個 for 循環(huán),按相反順序?qū)⒚總€對象插入到一個新的 ArrayList 中,但是 3、4 次重復(fù)這樣做之后,就會覺得很麻煩。

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


清單 3. ReverseIterator
public class ReverseIterator
            {
            public static void main(String[] args)
            {
            Person ted = new Person("Ted", "Neward", 39,
            new Person("Michael", "Neward", 16),
            new Person("Matthew", "Neward", 10));
            // Make a copy of the List
            List<Person> kids = new ArrayList<Person>(ted.getChildren());
            // Reverse it
            Collections.reverse(kids);
            // Display it
            System.out.println(kids);
            }
            }

Collections 類有很多這樣的 “算法”,它們被實現(xiàn)為靜態(tài)方法,以 Collections 作為參數(shù),提供獨立于實現(xiàn)的針對整個集合的行為。

而且,由于很棒的 API 設(shè)計,我們不必完全受限于 Collections 類中提供的算法 — 例如,我喜歡不直接修改(傳入的 Collection 的)內(nèi)容的方法。所以,可以編寫定制算法是一件很棒的事情,例如清單 4 就是一個這樣的例子:


清單 4. ReverseIterator 使事情更簡單
class MyCollections
            {
            public static <T> List<T> reverse(List<T> src)
            {
            List<T> results = new ArrayList<T>(src);
            Collections.reverse(results);
            return results;
            }
            }
            


5. 擴展 Collections API

以上定制算法闡釋了關(guān)于 Java Collections API 的一個最終觀點:它總是適合加以擴展和修改,以滿足開發(fā)人員的特定目的。

例如,假設(shè)您需要 Person 類中的孩子總是按年齡排序。雖然可以編寫代碼一遍又一遍地對孩子排序(也許是使用 Collections.sort 方法),但是通過一個 Collection 類來自動排序要好得多。

實際上,您甚至可能不關(guān)心是否每次按固定的順序?qū)ο蟛迦氲?Collection 中(這正是 List 的基本原理)。您可能只是想讓它們按一定的順序排列。

java.util 中沒有 Collection 類能滿足這些需求,但是編寫一個這樣的類很簡單。只需創(chuàng)建一個接口,用它描述 Collection 應(yīng)該提供的抽象行為。對于 SortedCollection,它的作用完全是行為方面的。


清單 5. SortedCollection
public interface SortedCollection<E> extends Collection<E>
            {
            public Comparator<E> getComparator();
            public void setComparator(Comparator<E> comp);
            }
            

編寫這個新接口的實現(xiàn)簡直不值一提:


清單 6. ArraySortedCollection
import java.util.*;
            public class ArraySortedCollection<E>
            implements SortedCollection<E>, Iterable<E>
            {
            private Comparator<E> comparator;
            private ArrayList<E> list;
            public ArraySortedCollection(Comparator<E> c)
            {
            this.list = new ArrayList<E>();
            this.comparator = c;
            }
            public ArraySortedCollection(Collection<? extends E> src, Comparator<E> c)
            {
            this.list = new ArrayList<E>(src);
            this.comparator = c;
            sortThis();
            }
            public Comparator<E> getComparator() { return comparator; }
            public void setComparator(Comparator<E> cmp) { comparator = cmp; sortThis(); }
            public boolean add(E e)
            { boolean r = list.add(e); sortThis(); return r; }
            public boolean addAll(Collection<? extends E> 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<E> iterator() { return list.iterator(); }
            public int size() { return list.size(); }
            public Object[] toArray() { return list.toArray(); }
            public <T> T[] toArray(T[] a) { return list.toArray(a); }
            public boolean equals(Object o)
            {
            if (o == this)
            return true;
            if (o instanceof ArraySortedCollection)
            {
            ArraySortedCollection<E> rhs = (ArraySortedCollection<E>)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);
            }
            }

這個實現(xiàn)非常簡陋,編寫時并沒有考慮優(yōu)化,顯然還需要進行重構(gòu)。但關(guān)鍵是 Java Collections API 從來無意將與集合相關(guān)的任何東西定死。它總是需要擴展,同時也鼓勵擴展。

當然,有些擴展比較復(fù)雜,例如 java.util.concurrent 中引入的擴展。但是另一些則非常簡單,只需編寫一個定制算法,或者已有 Collection 類的簡單的擴展。

擴展 Java Collections API 看上去很難,但是一旦開始著手,您會發(fā)現(xiàn)遠不如想象的那樣難。


結(jié)束語

和 Java Serialization 一樣,Java Collections API 還有很多角落等待有人去探索 —正因為如此,我們還不準備結(jié)束這個話題。在 5 件事 系列 的下一篇文章中,將可以看到用 Java Collections API 做更多事情的 5 種新的方式。 

本站僅提供存儲服務(wù),所有內(nèi)容均由用戶發(fā)布,如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點擊舉報。
打開APP,閱讀全文并永久保存 查看更多類似文章
猜你喜歡
類似文章
ArrayList 實現(xiàn) iterator()
您不知道的 5 件事……: Java Collections API,第 2 部分
java for in
Java容器類學(xué)習(xí)心得,歡迎拍磚
day13【Collection、泛型】
Java程序員集合框架面試題
更多類似文章 >>
生活服務(wù)
分享 收藏 導(dǎo)長圖 關(guān)注 下載文章
綁定賬號成功
后續(xù)可登錄賬號暢享VIP特權(quán)!
如果VIP功能使用有故障,
可點擊這里聯(lián)系客服!

聯(lián)系客服