轉載請註明原創出處,謝謝!java
人生的大道上默默地走,就必需要有一盞燈亮着爲你引導方向!而這盞燈抑或只是一句話,一句鼓勵,一個讚美,一次認可,一次承認,一次相識一次交流……sql
上篇文章:阿里JAVA開發手冊零度的思考理解(一) 獲得做者孤盡的確定支持,那是一個小激動啊,我會繼續努力,繼續閱讀和思考阿里JAVA開發手冊,畢竟每一條都是前人踩過的坑,經過血的教訓總結出來的。數據庫
看完這條,我的以爲主要是集合相關操做,在JAVA基礎中集合這塊的重要性也的確很是重要(畢竟是用到最多的),本期只會結合上題進行一些簡單擴展,並不會涵蓋全部集合操做,也不涉及集合是否線程安全這塊,後期我會在個人系列高併發、鎖系列裏擴展深刻。數組
已經有數組了爲何會出現集合呢?依然清晰的記得數據結構裏面順序結構、鏈式結構的特色。在這裏數組就屬於順序結構(可是集合裏面根據順序結構或者鏈式結構實現的都有,因此在選擇用那個的時候最起碼須要有那麼一點點思考而不是拿什麼用什麼)。安全
數組一旦定義,長度將不能再變化。而且數組僅僅是一個一連串的變量而已,對於不少重複的操做(並無進行統一的抽象)並且有些順序結構並不太適合,須要鏈式結構實現適合或者是須要順序結構與鏈式結構結合實現才比較合適。微信
備註:對於不少重複的操做,好比若是須要擴容,須要本身實現,根據編碼水平不一樣實現的效率不同(並且這個可能大量存在,每一個人都須要實現,不符合工程學的思想),再好比須要排序,增刪,遍歷等等。數據結構
上面的一些問題就引入了集合而且解決了這些問題,因此集合很是重要,而且項目中集合處處可見,須要把db,nosql裏面的數據接收下來。併發
下面看看集合具有的幾個特性 :框架
集合遍歷,從工程學咱們須要提供一種方法順序訪問一個集合對象中的各各元素,而又不須要暴露該對象的內部表示。nosql
如何才能作到呢??? 迭代器模式就能夠作到,下面帶你們一塊兒去了解下。
迭代器模式的功能主要在於提供對聚合對象的迭代訪問。主要就是這個訪問進行作文章的。那麼爲何使用迭代器模式呢?有什麼好處呢?
備註:迭代器模式的關鍵思想就是把對集合對象的遍歷和訪問從集合對象中分離出來,放到單獨的迭代器中,這樣集合對象會變得簡單一些;而迭代器和集合對象能夠獨立的變化和發展,這樣就大大加強類系統的靈活性。
通常狀況下面,使用的都是外部迭代器(由客戶端來控制迭代器的下一個元素的步驟,就是在代碼裏面咱們須要手動調用next來迭代下一個元素,這樣作就是要靈活點)
備註:經過使用javap查看反編譯代碼,在數組裏面,是固有的foreach實現,直接循環數組,而在容器的迭代foreach是經過迭代器來實現。
在稍微多作點鋪墊
備註:ArrayList裏面對Iterator實現了2種,一種是普通的從前向後,而第二種是雙向迭代輸出,能夠從往前也能夠日後。
上面說了那麼多,我以爲如今能夠開始解題了,各位看官久等了。併發系列又是另一個重要的話題,先不考慮併發進行分析,若是併發操做,須要對Iterator對象加鎖,這個應該好理解。
This field is used by the iterator and list iterator implementation returned by the iterator and listIterator methods. If the value of this field changes unexpectedly, the iterator (or list iterator) will throw a ConcurrentModificationException in response to the next, remove, previous, set or add operations. This provides fail-fast behavior, rather than non-deterministic behavior in the face of concurrent modification during iteration.
Use of this field by subclasses is optional. If a subclass wishes to provide fail-fast iterators (and list iterators), then it merely has to increment this field in its add(int, E) and remove(int) methods (and any other methods that it overrides that result in structural modifications to the list). A single call to add(int, E) or remove(int) must add no more than one to this field, or the iterators (and list iterators) will throw bogus ConcurrentModificationExceptions. If an implementation does not wish to provide fail-fast iterators, this field may be ignored.
因此應該注意,並不只僅包括remove,add元素也請使用Iterator方式。
這一條標準是加了強制的,說明了重要性,按照上面的優秀實踐去作就對了。
public static void main(String[] args) {
List<String> list = new ArrayList<String>();
list.add("1");
list.add("2");
for(String item:list){
if("1".equals(item)){ //(1 換成 if("2".equals(item)){
list.remove(item);
}
}
}複製代碼
當(1 換成 if("2".equals(item)){ 以後,運行結果報異常,結果如圖:
其實這種給出了錯誤,而且有代碼行數的狀況其實發現查找問題都挺方便的,其實該問題的重點就變成了都是基於Iterator的輸出,可是在進行刪除元素的時候應該用那種方式才正確。
沒有必要糾結爲何1不錯,而2錯,稍微看下源碼就知道了,其實咱們也可讓2不錯,只是jdk裏面就是這樣實現的,它的解釋和考慮以下緣由。
ArrayList此類的 iterator 和 listIterator 方法返回的迭代器是快速失敗的:在建立迭代器以後,除非經過迭代器自身的 remove 或 add 方法從結構上對列表進行修改,不然在任什麼時候間以任何方式對列表進行修改,迭代器都會拋出 ConcurrentModificationException。所以,面對併發的修改,迭代器很快就會徹底失敗,而不是冒着在未來某個不肯定時間發生任意不肯定行爲的風險。
因此最佳實踐就按照阿里java開發手冊裏面那樣就行了,add元素也請使用Iterator方式。
可能說完,你們感受迭代器就僅僅在集合遍歷裏面用,並且都已經有了,其實實際中的確有一些用法,反正都是圍繞控制訪問的,好比分頁,很是常見的狀況,若是每次都基於數據庫分頁那麼怕性能很差,若是徹底在內存(內存太貴,數據太多,不現實),通常的作法就是好比一頁20條數據,咱們通常能夠每次查詢數據庫的時候取5頁到內存(具體每次取多少能夠根據用戶行爲分析,獲得一個比較合理的,並且越到後面訪問的機會越少,取到內存的就越少了,能夠先好比每次都是取n頁數據,在多少頁以後每次取m頁 以後在每次取一頁一頁了。n>m>1)。那麼好比取出來的100條數據在內存中,須要進行根據分頁訪問,而原來的jdk裏面的好像不知足,那麼本身實現一個相似的是否是特別靈活呢?後續有空,我會在個人微信公衆號,系列文章的技術思考裏面把相似這塊分析下的。
這是阿里JAVA開發手冊其中一條明細,期待你的留言和分析!!!
若是讀完以爲有收穫的話,歡迎點贊加關注。
查閱更多歷史,歡迎關注我的公衆號!!!