欧美一区二区三区老妇人-欧美做爰猛烈大尺度电-99久久夜色精品国产亚洲a-亚洲福利视频一区二区

Java應(yīng)該避免的坑有哪些

這篇文章將為大家詳細講解有關(guān)Java應(yīng)該避免的坑有哪些,文章內(nèi)容質(zhì)量較高,因此小編分享給大家做個參考,希望大家閱讀完這篇文章后對相關(guān)知識有一定的了解。

創(chuàng)新互聯(lián)專注于南部企業(yè)網(wǎng)站建設(shè),響應(yīng)式網(wǎng)站建設(shè),購物商城網(wǎng)站建設(shè)。南部網(wǎng)站建設(shè)公司,為南部等地區(qū)提供建站服務(wù)。全流程按需規(guī)劃網(wǎng)站,專業(yè)設(shè)計,全程項目跟蹤,創(chuàng)新互聯(lián)專業(yè)和態(tài)度為您提供的服務(wù)

 前言

前不久幫同事一起 review 一個 job 執(zhí)行緩慢的問題時發(fā)現(xiàn)不少朋友在擼碼實現(xiàn)功能時還是有需要細節(jié)不夠注意,于是便有了這篇文章。

ArrayList 踩坑

List<String> temp = new ArrayList() ;//獲取一批數(shù)據(jù)List<String> all = getData();for(String str : all) {    temp.add(str);}

首先大家看看這段代碼有什么問題嘛?

其實在大部分情況下這都是沒啥問題,無非就是循環(huán)的往 ArrayList 中寫入數(shù)據(jù)而已。

但在特殊情況下,比如這里的 getData() 返回數(shù)據(jù)非常巨大時后續(xù) temp.add(str) 就會有問題了。

比如我們在 review 代碼時發(fā)現(xiàn)這里返回的數(shù)據(jù)有時會高達 2000W,這時 ArrayList 寫入的問題就凸顯出來了。

填坑指南

大家都知道 ArrayList 是由數(shù)組實現(xiàn),而數(shù)據(jù)的長度有限;需要在合適的時機對數(shù)組擴容。

這里以插入到尾部為例 add(E e)。

Java應(yīng)該避免的坑有哪些
ArrayListtemp=newArrayList<>(2);temp.add("1");temp.add("2");temp.add("3");

當我們初始化一個長度為 2 的 ArrayList ,并往里邊寫入三條數(shù)據(jù)時 ArrayList 就得擴容了,也就是將之前的數(shù)據(jù)復(fù)制一份到新的數(shù)組長度為  3 的數(shù)組中。

Java應(yīng)該避免的坑有哪些

之所以是 3 ,是因為新的長度=原有長度 * 1.5

通過源碼我們可以得知 ArrayList 的默認長度為 10.

Java應(yīng)該避免的坑有哪些
Java應(yīng)該避免的坑有哪些

但其實并不是在初始化的時候就創(chuàng)建了 DEFAULT_CAPACITY=10 的數(shù)組。

Java應(yīng)該避免的坑有哪些

而是在往里邊 add 第一個數(shù)據(jù)的時候會擴容到 10.

既然知道了默認的長度為 10 ,那說明后續(xù)一旦寫入到第九個元素的時候就會擴容為  10*1.5=15。這一步為數(shù)組復(fù)制,也就是要重新開辟一塊新的內(nèi)存空間存放這 15 個數(shù)組。

一旦我們頻繁且數(shù)量巨大的進行寫入時就會導(dǎo)致許多的數(shù)組復(fù)制,這個效率是極低的。

但如果我們提前預(yù)知了可能會寫入多少條數(shù)據(jù)時就可以提前避免這個問題。

比如我們往里邊寫入 1000W 條數(shù)據(jù),在初始化的時候就給定數(shù)組長度與用默認 10 的長度之間性能是差距巨大的。

我用 JMH 基準測試驗證如下:

@Warmup(iterations = 5, time = 1, timeUnit = TimeUnit.SECONDS)@Measurement(iterations = 5, time = 1, timeUnit = TimeUnit.SECONDS)public class CollectionsTest {    private static final int TEN_MILLION = 10000000;    @Benchmark    @BenchmarkMode(Mode.AverageTime)    @OutputTimeUnit(TimeUnit.MICROSECONDS)    public void arrayList() {        List<String> array = new ArrayList<>();        for (int i = 0; i < TEN_MILLION; i++) {            array.add("123");        }    }    @Benchmark    @BenchmarkMode(Mode.AverageTime)    @OutputTimeUnit(TimeUnit.MICROSECONDS)    public void arrayListSize() {        List<String> array = new ArrayList<>(TEN_MILLION);        for (int i = 0; i < TEN_MILLION; i++) {            array.add("123");        }    }    public static void main(String[] args) throws RunnerException {        Options opt = new OptionsBuilder()                .include(CollectionsTest.class.getSimpleName())                .forks(1)                .build();        new Runner(opt).run();    }}
Java應(yīng)該避免的坑有哪些

根據(jù)結(jié)果可以看出預(yù)設(shè)長度的效率會比用默認的效率高上很多(這里的 Score 指執(zhí)行完函數(shù)所消耗的時間)。

所以這里強烈建議大家:在有大量數(shù)據(jù)寫入 ArrayList 時,一定要初始化指定長度。

再一個是一定要慎用 add(intindex,E element) 向指定位置寫入數(shù)據(jù)。

Java應(yīng)該避免的坑有哪些

通過源碼我們可以看出,每一次寫入都會將 index 后的數(shù)據(jù)往后移動一遍,其實本質(zhì)也是要復(fù)制數(shù)組;

但區(qū)別于往常規(guī)的往數(shù)組尾部寫入數(shù)據(jù),它每次都會進行數(shù)組復(fù)制,效率極低。

LinkedList

提到 ArrayList 就不得不聊下 LinkedList 這個孿生兄弟;雖說都是 List 的容器,但本質(zhì)實現(xiàn)卻完全不同。

Java應(yīng)該避免的坑有哪些

LinkedList 是由鏈表組成,每個節(jié)點又有頭尾兩個節(jié)點分別引用了前后兩個節(jié)點;因此它也是一個雙向鏈表。

所以理論上來說它的寫入非常高效,將不會有 ArrayList 中效率極低的數(shù)組復(fù)制,每次只需要移動指針即可。

這里偷懶就不畫圖了,大家自行腦補下。

對比測試

坊間一直流傳:

LinkedList 的寫入效率高于 ArrayList,所以在寫大于讀的時候非常適用于 LinkedList 。

@Benchmark    @BenchmarkMode(Mode.AverageTime)    @OutputTimeUnit(TimeUnit.MICROSECONDS)    public void linkedList() {        List<String> array = new LinkedList<>();        for (int i = 0; i < TEN_MILLION; i++) {            array.add("123");        }    }
Java應(yīng)該避免的坑有哪些

這里測試看下結(jié)論是否符合;同樣的也是對 LinkedList 寫入 1000W 次數(shù)據(jù),通過結(jié)果來看初始化數(shù)組長度的 ArrayList 效率明顯是要高于  LinkedList 。

但這里的前提是要提前預(yù)設(shè) ArrayList 的數(shù)組長度,避免數(shù)組擴容,這樣 ArrayList 的寫入效率是非常高的,而 LinkedList  的雖然不需要復(fù)制內(nèi)存,但卻需要創(chuàng)建對象,變換指針等操作。

而查詢就不用多說了, ArrayList 可以支持下標隨機訪問,效率非常高。

LinkedList 由于底層不是數(shù)組,不支持通過下標訪問,而是需要根據(jù)查詢 index 所在的位置來判斷是從頭還是從尾進行遍歷。

Java應(yīng)該避免的坑有哪些

但不管是哪種都得需要移動指針來一個個遍歷,特別是 index 靠近中間位置時將會非常慢。

高性能應(yīng)用都是從小細節(jié)一點點堆砌起來的,就如這里提到的 ArrayList  的坑一樣,日常使用沒啥大問題,一旦數(shù)據(jù)量起來所有的小問題都會成為大問題。

  • 再使用 ArrayList 時如果能提前預(yù)測到數(shù)據(jù)量大小,比較大時一定要指定其長度。

  • 盡可能避免使用 add(index,e) api,會導(dǎo)致復(fù)制數(shù)組,降低效率。

  • 再額外提一點,我們常用的另一個 Map 容器 HashMap 也是推薦要初始化長度從而避免擴容。

關(guān)于Java應(yīng)該避免的坑有哪些就分享到這里了,希望以上內(nèi)容可以對大家有一定的幫助,可以學(xué)到更多知識。如果覺得文章不錯,可以把它分享出去讓更多的人看到。

當前文章:Java應(yīng)該避免的坑有哪些
網(wǎng)址分享:http://chinadenli.net/article8/giisip.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供、品牌網(wǎng)站制作、微信公眾號網(wǎng)站設(shè)計公司、動態(tài)網(wǎng)站、服務(wù)器托管

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時需注明來源: 創(chuàng)新互聯(lián)

營銷型網(wǎng)站建設(shè)