阿裡JAVA開發手冊零度的思考理解(二)

来源:http://www.cnblogs.com/lirenzuo/archive/2017/11/04/7783998.html
-Advertisement-
Play Games

轉載請註明原創出處,謝謝! 說在前面 人生的大道上默默地走,就必須要有一盞燈亮著為你引導方向!而這盞燈抑或只是一句話,一句鼓勵,一個贊美,一次承認,一次認可,一次相識一次交流…… 上篇文章: "阿裡JAVA開發手冊零度的思考理解(一) " 得到作者 孤盡 的肯定支持,那是一個小激動啊,我會繼續努力, ...


轉載請註明原創出處,謝謝!

說在前面

人生的大道上默默地走,就必須要有一盞燈亮著為你引導方向!而這盞燈抑或只是一句話,一句鼓勵,一個贊美,一次承認,一次認可,一次相識一次交流……

上篇文章:阿裡JAVA開發手冊零度的思考理解(一)得到作者孤盡的肯定支持,那是一個小激動啊,我會繼續努力,繼續閱讀和思考阿裡JAVA開發手冊,畢竟每一條都是前人踩過的坑,通過血的教訓總結出來的。

上篇題目回顧

阿裡JAVA開發手冊

看完這條,個人覺得主要是集合相關操作,在JAVA基礎中集合這塊的重要性也的確非常重要(畢竟是用到最多的),本期只會結合上題進行一些簡單擴展,並不會涵蓋所有集合操作,也不涉及集合是否線程安全這塊,後期我會在我的系列高併發、鎖系列里擴展深入。

集合的重要性

已經有數組了為什麼會出現集合呢?依然清晰的記得數據結構裡面順序結構、鏈式結構的特點。在這裡數組就屬於順序結構(但是集合裡面根據順序結構或者鏈式結構實現的都有,所以在選擇用那個的時候最起碼需要有那麼一點點思考而不是拿什麼用什麼)。

數組一旦定義,長度將不能再變化。並且數組僅僅是一個一連串的變數而已,對於很多重覆的操作(並沒有進行統一的抽象)而且有些順序結構並不太適合,需要鏈式結構實現適合或者是需要順序結構與鏈式結構結合實現才比較合適。

備註:對於很多重覆的操作,比如如果需要擴容,需要自己實現,根據編碼水平不同實現的效率不一樣(而且這個可能大量存在,每個人都需要實現,不符合工程學的思想),再比如需要排序,增刪,遍歷等等。

上面的一些問題就引入了集合併且解決了這些問題,所以集合非常重要,並且項目中集合到處可見,需要把db,nosql裡面的數據接收下來。

下麵看看集合具備的幾個特性 :

  • 這種框架是高性能的,對於基本集合(動態數組、鏈表、樹和散列表)的實現是高效的,並且是經過高度測試(不管是性能,安全等都是很可靠的)。
  • 集合允許不同類型的集合以相同的方式繼續操作。
  • 集合是容易擴展和修改的。

集合的遍歷思考

集合遍歷,從工程學我們需要提供一種方法順序訪問一個集合對象中的各各元素,而又不需要暴露該對象的內部表示

如何才能做到呢??? 迭代器模式就可以做到,下麵帶大家一起去瞭解下。

迭代器模式

迭代器模式的功能主要在於提供對聚合對象的迭代訪問。主要就是這個訪問進行做文章的。那麼為什麼使用迭代器模式呢?有什麼好處呢?

  • 集合對象的類型很多,如果對集合對象的迭代訪問跟集合對象本身融合在一起的話,會嚴重影響到集合對象的可擴展性和可維護性。

    備註:迭代器模式的關鍵思想就是把對集合對象的遍歷和訪問從集合對象中分離出來,放到單獨的迭代器中,這樣集合對象會變得簡單一些;而迭代器和集合對象可以獨立的變化和發展,這樣就大大增強類系統的靈活性。

一般情況下麵,使用的都是外部迭代器(由客戶端來控制迭代器的下一個元素的步驟,就是在代碼裡面我們需要手動調用next來迭代下一個元素,這樣做就是要靈活點)

  • JDK5之後引入的新特性foreach( 增強版for)

備註:通過使用javap查看反編譯代碼,在數組裡面,是固有的foreach實現,直接迴圈數組,而在容器的迭代foreach是通過迭代器來實現。

數組foreach

容器的迭代foreach

在稍微多做點鋪墊

  • ArrayList對Iterator介面實現

    備註:ArrayList裡面對Iterator實現了2種,一種是普通的從前向後,而第二種是雙向迭代輸出,可以從往前也可以往後。

解題

阿裡JAVA開發手冊

上面說了那麼多,我覺得現在可以開始解題了,各位看官久等了。併發系列又是另外一個重要的話題,先不考慮併發進行分析,如果併發操作,需要對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開發手冊

這是阿裡JAVA開發手冊其中一條明細,期待你的留言和分析!!!

如果讀完覺得有收穫的話,歡迎點贊加關註。


查閱更多歷史,歡迎關註個人公眾號!!!

匠心零度公眾號.jpg


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 首先我們先來瞭解下瀏覽器的緩存 瀏覽器緩存機制 Cache-control策略 Cache-Control與Expires的作用一致,都是指明當前資源的有效期,控制瀏覽器是否直接從瀏覽器緩存取數據還是重新發請求到伺服器取數據。只不過Cache-Control的選擇更多,設置更細緻,如果同時設置的話, ...
  • #include using namespace std; int main(){ int i,j; for(i=1;i<=60;i++){ for(j=1;j<=50;j++){ cout<<"*"; } cout<<endl; } } ...
  • 基礎數據類型包裝類 當一個程式要求互動式輸入一個int類型的年齡時,從文本框中輸入的結果肯定是String類型的。要在程式中進行相關操作,它必須先轉換為int類型。因此可以使用數據類型的轉換或強制轉換,但這種轉換方式太過簡單,功能太少,因此java中提供了數據類型包裝類的概念。 數據類型包裝類是指  ...
  • 本文從IO流的繼承體系方面做了簡要的說明,並對常見的IO流進行了介紹並提供了簡單的實例。 ...
  • 1.創建project 方法一:使用命令行創建項目。在D盤cmd執行如下命令: django-admin.py startproject myblog django-admin.py startproject myblog 方法二:使用pycharm創建項目。放置位置為D:\myblog 2.創建a ...
  • 無論何種語言,第一句代碼肯定是要寫“Hello World!”的 print ('Hello World!') 1>格式化輸出 運行截圖: 2>利用if,while語句寫的猜年齡游戲 3>調用getpass模塊,實現暗密碼登陸(這個getpass模塊在pycharm中不好使) ...
  • 項目簡介和code見《同步非同步和阻塞2-測試小項目》 1. 實現 1> 非同步線程IO處理 unsigned CAsyncIO::ThreadWork() { int nRet = IO(); //map is better than array at here, but it need STL un... ...
  • 題外話: Python版本:最新的3.6 安裝註意點:勾選添加路徑後自定義安裝到硬碟的一級目錄,例如本人的安裝路徑: F:\Python 原因:可以自動添加python環境變數,自動關聯.py文件,其餘的優點很多,例如學習selenium的,使用pip install selenium命令就可以安裝 ...
一周排行
    -Advertisement-
    Play Games
  • 問題 有很多應用程式在驗證JSON數據的時候用到了JSON Schema。 在微服務架構下,有時候各個微服務由於各種歷史原因,它們所生成的數據對JSON Object屬性名的大小寫規則可能並不統一,它們需要消費的JSON數據的屬性名可能需要大小寫無關。 遺憾的是,目前的JSON Schema沒有這方 ...
  • 首先下載centos07鏡像,建議使用阿裡雲推薦的地址: https://mirrors.aliyun.com/centos/7.9.2009/isos/x86_64/?spm=a2c6h.25603864.0.0.59b5f5ad5Nfr0X 其實這裡就已經出現第一個坑了 centos 07 /u ...
  • 相信很多.NETer看了標題,都會忍不住好奇,點進來看看,並且順便準備要噴作者! 這裡,首先要申明一下,作者本人也非常喜歡Linq,也在各個項目中常用Linq。 我愛Linq,Linq優雅萬歲!!!(PS:順便吐槽一下,隔壁Java從8.0版本推出的Streams API,抄了個四不像,一點都不優雅 ...
  • 在人生的重要時刻,我站在了畢業的門檻上,望著前方的道路,心中涌動著對未來的無限憧憬與些許忐忑。面前,兩條道路蜿蜒伸展:一是繼續在職場中尋求穩定,一是勇敢地走出一條屬於自己的創新之路。儘管面臨年齡和現實的挑戰,我仍舊選擇勇往直前,用技術這把鑰匙,開啟新的人生篇章。 迴首過去,我深知時間寶貴,精力有限。 ...
  • 單元測試 前言 時隔多個月,終於抽空學習了點新知識,那麼這次來記錄一下C#怎麼進行單元測試,單元測試是做什麼的。 我相信大部分剛畢業的都很疑惑單元測試是乾什麼的?在小廠實習了6個月後,我發現每天除了寫CRUD就是寫CRUD,幾乎用不到單元測試。寫完一個功能直接上手去測,當然這隻是我個人感受,僅供參考 ...
  • 一:背景 1. 講故事 最近在分析dump時,發現有程式的卡死和WeakReference有關,在以前只知道怎麼用,但不清楚底層邏輯走向是什麼樣的,藉著這個dump的契機來簡單研究下。 二:弱引用的玩法 1. 一些基礎概念 用過WeakReference的朋友都知道這裡面又可以分為弱短和弱長兩個概念 ...
  • 最近想把ET打表工具的報錯提示直接調用win系統彈窗,好讓策劃明顯的知道表格哪裡填錯數據,彈窗需要調用System.Windows.Forms庫。操作如下: 需要在 .csproj 文件中添加: <UseWindowsForms>true</UseWindowsForms> 須將目標平臺設置為 Wi ...
  • 從C#3開始,拓展方法這一特性就得到了廣泛的應用。 此功能允許你能夠使用實例方法的語法調用某個靜態方法,以下是一個獲取/創建文件的靜態方法: public static async Task<StorageFile> GetOrCreateFileAsync(this StorageFolder f ...
  • 在Windows 11下,使用WinUI2.6以上版本的ListView長這樣: 然而到了Win10上,儘管其他控制項的樣式沒有改變,但ListViewItem變成了預設樣式(初代Fluent) 最重大的問題是,Win10上的HorizontalAlignment未被設置成Stretch,可能造成嚴重 ...
  • 前言 周六在公司加班,幹完活後越顯無聊,想著下載RabbiitMQ做個小項目玩玩。然而這一下就下載了2個小時,真讓人頭痛。 簡單的講一下如何安裝吧,網上教程和踩坑文章還是很多的,我講我感覺有用的文章放在本文末尾。 安裝地址 erlang 下載 - Erlang/OTP https://www.erl ...