Java dizisi veya liste. Hangisi daha hızlı?

Ben Java seri olarak erişilebilir bellekte dizeleri binlerce tutmak zorunda. Onları bir dizide saklamalı mıyım yoksa bir çeşit liste kullanmalı mıyım ?

diziler tüm verileri bitişik bir bellek yığınında tuttuğundan (listelerin aksine), binlerce dizeyi depolamak için bir dizinin kullanılması sorunlara neden olur mu ?

cevap: ortak görüş birliği, performans farkının küçük olmasıdır. Liste arayüzü daha fazlasını sağlar esneklik.

316
tarihinde sordu Roman Nikitchenko 2009-04-04 09:57:28
kaynak

30 ответов

daha hızlı olan test etmek için bir profiler kullanmanızı öneririm.

benim kişisel görüşüm listeleri kullanmanız gerektiğidir.

büyük bir kod tabanı ve ve dizilerini kullanan önceki bir geliştirici grubu üzerinde çalışıyorum . Kodu çok esnek yaptı. Büyük parçalarını listelere değiştirdikten sonra hız fark etmedik.

334
cevap Fortyrunner 2009-04-04 10:18:14
kaynak

Java yolu, soyutlama verilerinin ihtiyaçlarınıza en uygun olduğunu düşünmelisiniz. Java'da bir listenin somut bir veri türü değil soyut olduğunu unutmayın. Dizeleri bir liste olarak bildirmeli ve ArrayList uygulamasını kullanarak başlatmalısınız.

List<String> strings = new ArrayList<String>();

soyut veri türü ve özel uygulama bu ayırma nesne yönelimli programlama önemli yönlerinden biridir.

An ArrayList temel uygulama olarak bir dizi kullanarak liste soyut veri türünü uygular. Erişim hızı, bir diziye hemen hemen aynıdır ve öğeleri bir listeye ekleyebilme ve çıkarma ek avantajlarıyla (bu bir ArrayList ile bir O(n) işlemi olmasına rağmen) ve altta yatan uygulamayı daha sonra değiştirmeye karar verirseniz yapabilirsiniz. Örneğin, eşitlenmiş erişime ihtiyacınız olduğunu fark ederseniz, tüm yeniden yazmadan uygulamayı bir vektöre değiştirebilirsiniz kodunuz.

aslında, ArrayList özellikle çoğu bağlamlarda düşük seviyeli dizi yapısını değiştirmek için tasarlanmıştır. Java bugün tasarlandıysa, dizilerin ArrayList yapısı lehine tamamen bırakılması tamamen mümkündür.

diziler tüm verileri bitişik bir bellek yığınında tuttuğundan (listelerin aksine), binlerce dizeyi depolamak için bir dizinin kullanılması sorunlara neden olur mu ?

Java'da, tüm koleksiyonlar yalnızca nesnelere değil, nesnelere atıfta bulunur. Hem diziler hem de ArrayList bitişik bir dizide birkaç bin referans depolayacak, bu yüzden esasen aynıdır. Birkaç bin 32-bit referansın bitişik bir bloğunun her zaman modern donanım üzerinde hazır olacağını düşünebilirsiniz. Bu, tabii ki, sadece bitişik bellek bloğunun tamamen belleğin tükenmeyeceğini garanti etmez gereklilik fufil zor değildir.

152
cevap cygil 2009-04-05 04:19:54
kaynak

diziler üzerinde genel türleri tercih etmelisiniz. Diğerleri tarafından belirtildiği gibi, diziler esnek değildir ve genel türlerin ifade gücüne sahip değildir. (Ancak çalışma zamanı typechecking'i destekliyorlar, ancak bu genel türlerle kötü bir şekilde karışıyor.)

ancak, her zaman olduğu gibi, optimize ederken her zaman şu adımları izlemelisiniz:

  • güzel, temiz ve kodunuzun sürümünü çalışana kadar optimize etmeyin. Genel türlere değiştirme, bu adımda zaten motive olabilir.
  • güzel ve temiz bir sürümünüz olduğunda, yeterince hızlı olup olmadığına karar verin.
  • yeterince hızlı değilse, performansını ölçün . Bu adım iki nedenden dolayı önemlidir. Ölçmezseniz, (1) yaptığınız herhangi bir optimizasyonun etkisini bilemezsiniz ve (2) nerede optimize edileceğini bilemezsiniz.
  • - senin en sıcak parçası kod.
  • tekrar ölçün. bu daha önce ölçme kadar önemlidir. Optimizasyon şeyleri iyileştirmediyse, geri döndürür . Unutmayın, kod olmadan optimizasyon oldu temiz, güzel, ve çalışma.
90
cevap JesperE 2015-05-06 04:35:51
kaynak

ArrayList kullanmayı öneren cevaplar çoğu senaryoda mantıklı olsa da, göreceli performansın gerçek sorusu gerçekten cevaplanmamıştır.

bir dizi ile yapabileceğiniz birkaç şey var:

  • oluştur
  • bir öğeyi ayarla
  • bir öğeyi al
  • klon / kopyala

Genel sonuç

get ve set işlemleri bir ArrayList (resp. Makinemde arama başına 1 ve 3 nanosaniye), yoğun olmayan herhangi bir kullanım için bir ArrayList vs. bir dizi kullanmanın çok az yükü vardır. ancak akılda tutulması gereken birkaç şey vardır:

  • bir listede yeniden boyutlandırma işlemleri ( list.add(...) çağırırken ) maliyetlidir ve başlangıç kapasitesini bir anda ayarlamaya çalışmalıdır mümkün olduğunda yeterli seviye (bir dizi kullanırken aynı sorunun ortaya çıktığını unutmayın)
  • ilkellerle uğraşırken, diziler çok daha hızlı olabilir, çünkü
  • sadece bir ArrayList değerleri alır/ayarlar bir uygulama (çok yaygın değil!)
  • dizisine geçerek %25'ten fazla bir performans kazancı görebiliyordu

detaylı bilgi

işte standart bir x86 masaüstü makinesinde JDK 7 ile jmh kıyaslama Kütüphanesi (nanosaniye süreleri) kullanarak bu üç işlem için ölçülen sonuçlar. ArrayList sonuçları karşılaştırılabilir olduğundan emin olmak için testlerde yeniden boyutlandırılır asla unutmayın. Benchmark kodu burada .

Array / ArrayList Creation

4 testleri çalıştırdım, aşağıdaki ifadeleri çalıştırdım:

  • createArray1: Integer[] array = new Integer[1];
  • createList1: List<Integer> list = new ArrayList<> (1);
  • createArray10000: Integer[] array = new Integer[10000];
  • createList10000: List<Integer> list = new ArrayList<> (10000);

sonuçlar (çağrı başına nanosaniye, %95 güven):

a.p.g.a.ArrayVsList.CreateArray1         [10.933, 11.097]
a.p.g.a.ArrayVsList.CreateList1          [10.799, 11.046]
a.p.g.a.ArrayVsList.CreateArray10000    [394.899, 404.034]
a.p.g.a.ArrayVsList.CreateList10000     [396.706, 401.266]

sonuç: hiçbir fark .

get operations

aşağıdaki ifadeleri yürüterek 2 test çalıştırdım:

  • getList: return list.get(0);
  • getArray: return array[0];

sonuçlar (çağrı başına nanosaniye, %95 güven):

a.p.g.a.ArrayVsList.getArray   [2.958, 2.984]
a.p.g.a.ArrayVsList.getList    [3.841, 3.874]

sonuç: bir diziden elde etmek, bir diziden elde etmekten yaklaşık %25 daha hızlıdır , ancak fark yalnızca bir nanosaniye sırasına bağlıdır.

set işlemleri

aşağıdaki ifadeleri yürüterek 2 test çalıştırdım:

  • setList: list.set(0, value);
  • setArray: array[0] = value;

sonuçlar (arama başına nanosaniye cinsinden):

a.p.g.a.ArrayVsList.setArray   [4.201, 4.236]
a.p.g.a.ArrayVsList.setList    [6.783, 6.877]

sonuç: diziler üzerindeki set işlemleri, listelerden yaklaşık %40 daha hızlıdır , ancak get'e gelince, her set operasyon birkaç nanosaniye alır-farkın 1 saniyeye ulaşması için, yüz milyonlarca kez listede/dizide öğeleri ayarlamanız gerekir!

klon / kopya

Arraylist'in kopya Oluşturucusu Arrays.copyOf ile ilişkilendirilir, bu nedenle performans dizi kopyasıyla aynıdır ( clone , Arrays.copyOf veya System.arrayCopy ile bir dizi kopyalamak hiçbir maddi fark yaratmaz performans-bilge ).

80
cevap assylias 2017-05-23 15:10:29
kaynak

sanırım orijinal poster, bazı karışıklıklara neden olan bir C++/STL arka planından geliyor. C++ std::list iki kat bağlantılı bir listedir.

Java [java.util.]List bir uygulama-ücretsiz arayüzü (C++ açısından saf soyut sınıf) ' dir. List çift bağlantılı bir liste olabilir - java.util.LinkedList sağlanır. Bununla birlikte , 100'den 99 kez yeni bir List yapmak istediğinizde, bunun yerine java.util.ArrayList kullanmak istersiniz, bu da kaba eşdeğerdir C++ std::vector . java.util.Collections.emptyList() ve java.util.Arrays.asList() tarafından döndürülen gibi diğer standart uygulamalar vardır .

bir performans açısından bir arabirim ve ekstra bir nesne üzerinden gitmek zorunda çok küçük bir isabet vardır, ancak çalışma zamanı uzanmış bu nadiren herhangi bir önemi vardır anlamına gelir. Ayrıca String genellikle bir nesne artı dizisi olduğunu unutmayın. Yani her giriş için, muhtemelen iki başka nesne var. C++ std::vector<std::string> , kopyalama rağmen gibi bir işaretçi olmayan değerle, karakter dizileri dize için bir nesne oluşturur (ve bunlar genellikle paylaşılmaz).

bu özel kod gerçekten performansa duyarlı ise, tüm dizelerin tüm karakterleri ve daha sonra bir dizi ofset için tek bir char[] dizisi (veya byte[] ) oluşturabilirsiniz. IIRC, javac'ın nasıl uygulandığı budur.

22
cevap Tom Hawtin - tackline 2015-10-07 15:07:54
kaynak

öncelikle, klasik comp sci veri yapıları anlamında (yani bağlantılı bir liste) "liste" anlamına gelir mi yoksa java'yı mı kastediyorsunuz?utıl.Liste mi? Java demek istiyorsan.utıl.Liste, bu bir arayüz. Bir dizi kullanmak istiyorsanız, ArrayList uygulamasını kullanın ve dizi benzeri davranış ve semantik alırsınız. Sorun çözüldü.

bir diziyi bağlantılı bir listeye karşı kastediyorsanız, Big O'ya geri döndüğümüz biraz farklı bir argümandır (işte bir düz İngilizce açıklama bu yabancı bir terim ise.

dizisi;

  • Rastgele Erişim: O(1);
  • Ekle: O (n);
  • Sil: O(n).

Bağlantılı Liste:

  • rastgele erişim: O(n);
  • Ekle: O (1);
  • Sil: O(1).

Yani diziyi yeniden boyutlandırma nasıl en uygun hangisi seçin. Yeniden boyutlandırırsanız, çok şey ekleyin ve silin, belki de bağlantılı bir liste daha iyi bir seçimdir. Rastgele erişim nadir ise aynı şey için de geçerlidir. Seri erişimden söz ediyorsun. Esas olarak çok az değişiklik ile seri erişim yapıyorsanız, muhtemelen hangisini seçtiğinizin önemi yoktur.

bağlantılı listeler biraz daha yüksek bir yüke sahiptir, çünkü söylediğiniz gibi, potansiyel olarak bitişik olmayan bellek bloklarıyla uğraşıyorsunuz ve (1) Bir sonraki öğeye işaretçiler. Bununla birlikte, milyonlarca girişle uğraşmadığınız sürece muhtemelen önemli bir faktör değildir.

11
cevap cletus 2017-05-23 13:31:12
kaynak

Arraylists'i dizilerle karşılaştırmak için küçük bir kriter yazdım. Eski ish dizüstü bilgisayarımda, 5000 elementli bir arraylist, 1000 kez geçme zamanı, eşdeğer dizi kodundan yaklaşık 10 milisaniye daha yavaştı.

yani, listeyi yinelemekten başka bir şey yapmıyorsanız ve çok şey yapıyorsanız, belki optimizasyona değer. Aksi takdirde listeyi kullanırdım, çünkü yaparken daha kolay hale gelecektir kodu optimize etmeniz gerekiyor.

n.b. , kullanarak for String s: stringsList listesine erişmek için eski stil for-loop kullanmaktan yaklaşık %50 daha yavaş olduğunu fark ettim. Hadi bakalım... İşte zamanlanmış iki işlev; dizi ve liste 5000 rastgele (farklı) dizeyle dolduruldu.

private static void readArray(String[] strings) {
    long totalchars = 0;
    for (int j = 0; j < ITERATIONS; j++) {
        totalchars = 0;
        for (int i = 0; i < strings.length; i++) {
            totalchars += strings[i].length();

        }
    }
}

private static void readArrayList(List<String> stringsList) {
    long totalchars = 0;
    for (int j = 0; j < ITERATIONS; j++) {
        totalchars = 0;
        for (int i = 0; i < stringsList.size(); i++) {
            totalchars += stringsList.get(i).length();
        }
    }
}
11
cevap Chris May 2009-04-04 18:44:33
kaynak

çoğu durumda Diziler üzerinde Dizilenlerin esnekliğini ve zarafetini seçmeniz gerektiğini kabul ediyorum-ve çoğu durumda program performansına etkisi ihmal edilebilir olacaktır.

bununla birlikte, yazılım grafik oluşturma veya özel bir sanal makine için az yapısal değişiklik (ekler ve kaldırır) ile sabit, ağır yineleme yapıyorsanız, sıralı erişim kıyaslama testlerim dizilerinin dizilerden 1.5 x daha yavaş olduğunu gösteriyor sistemimde (bir yaşındaki imac'imde Java 1.6).

bazı kod:

import java.util.*;

public class ArrayVsArrayList {
    static public void main( String[] args ) {

        String[] array = new String[300];
        ArrayList<String> list = new ArrayList<String>(300);

        for (int i=0; i<300; ++i) {
            if (Math.random() > 0.5) {
                array[i] = "abc";
            } else {
                array[i] = "xyz";
            }

            list.add( array[i] );
        }

        int iterations = 100000000;
        long start_ms;
        int sum;

        start_ms = System.currentTimeMillis();
        sum = 0;

        for (int i=0; i<iterations; ++i) {
          for (int j=0; j<300; ++j) sum += array[j].length();
        }

        System.out.println( (System.currentTimeMillis() - start_ms) + " ms (array)" );
        // Prints ~13,500 ms on my system

        start_ms = System.currentTimeMillis();
        sum = 0;

        for (int i=0; i<iterations; ++i) {
          for (int j=0; j<300; ++j) sum += list.get(j).length();
        }

        System.out.println( (System.currentTimeMillis() - start_ms) + " ms (ArrayList)" );
        // Prints ~20,800 ms on my system - about 1.5x slower than direct array access
    }
}
11
cevap AbePralle 2017-03-21 21:46:29
kaynak

hayır, çünkü teknik olarak, dizi yalnızca dizelere referans depolar. Dizelerin kendileri farklı bir konumda tahsis edilir. Bin öğe için, bir listenin daha iyi olacağını söyleyebilirim, daha yavaştır, ancak daha fazla esneklik sunar ve özellikle bunları yeniden boyutlandıracaksanız kullanmak daha kolaydır.

6
cevap CookieOfFortune 2009-04-04 10:02:00
kaynak

binlerce varsa, bir trie kullanmayı düşünün. Bir trie, depolanan dizenin ortak öneklerini birleştiren ağaç benzeri bir yapıdır.

örneğin, dizeler

ise
intern
international
internationalize
internet
internets

the trie would store:

intern
 -> '151910920'
 international
 -> '151910920'
 -> ize'151910920'
 net
 ->'151910920'
 ->s'151910920'

dizeler, depolama için 57 karakter (null sonlandırıcı, '\0' dahil) ve bunları tutan dize nesnesinin boyutu ne olursa olsun gerektirir. (Aslında, muhtemelen yuvarlamalıyız 16 katları kadar tüm boyutları, ama...) Kabaca 57 + 5 = 62 bayt diyoruz.

trie, depolama için 29 (null sonlandırıcı,' \0 ' dahil) gerektirir, artı sizeof bir dizi ve alt trie düğümlerinin bir listesi için bir ref olan trie düğümleri.

bu örnek için muhtemelen aynı çıkıyor; binlerce için, muhtemelen ortak önekleriniz olduğu sürece daha az çıkıyor.

şimdi, diğer kodda trie kullanırken, muhtemelen bir aracı olarak bir StringBuffer kullanarak dize dönüştürmek gerekir. Dizelerin çoğu aynı anda dizeler olarak kullanılıyorsa, trie dışında, bu bir kayıptır.

ama sadece o zaman birkaç kullanıyorsanız-diyelim ki, bir sözlükte şeyler aramak için-trie size çok yer kazandırabilir. Onları bir Hashset'te saklamaktan kesinlikle daha az yer.

onlara "seri olarak" eriştiğinizi söylüyorsunuz - eğer bu sırayla alfabetik olarak ifade edilirse, eğer derinlik-ilk yinelemek eğer trie de açıkçası, size ücretsiz alfabetik sipariş verir.

5
cevap tpdi 2009-04-05 04:55:14
kaynak

güncelleme:

Mark'ın belirttiği gibi

, JVM ısındıktan sonra önemli bir fark yoktur (birkaç test geçer). Yeni matris satırından başlayarak yeniden oluşturulan Dizi veya hatta yeni geçiş ile kontrol edildi. Büyük olasılıkla bu işaretlerle dizin erişimi olan basit dizi koleksiyonları lehine kullanılacak değildir.

hala ilk 1-2 basit dizi geçer 2-3 kat daha hızlıdır.

ORİJİNAL YAZI:

için çok fazla kelime konu kontrol etmek için çok basit. herhangi bir soru dizisi olmadan herhangi bir sınıf kapsayıcı birkaç kat daha hızlıdır. Performans kritik bölümüm için alternatifler arayan bu soruyu çalıştırıyorum. İşte gerçek durumu kontrol etmek için inşa ettiğim prototip kodu:

import java.util.List;
import java.util.Arrays;

public class IterationTest {

    private static final long MAX_ITERATIONS = 1000000000;

    public static void main(String [] args) {

        Integer [] array = {1, 5, 3, 5};
        List<Integer> list = Arrays.asList(array);

        long start = System.currentTimeMillis();
        int test_sum = 0;
        for (int i = 0; i < MAX_ITERATIONS; ++i) {
//            for (int e : array) {
            for (int e : list) {
                test_sum += e;
            }
        }
        long stop = System.currentTimeMillis();

        long ms = (stop - start);
        System.out.println("Time: " + ms);
    }
}

ve işte cevap:

diziye dayalı (hat 16 aktiftir):

Time: 7064

listeye göre (hat 17 aktif):

Time: 20950

daha hızlı ' hakkında daha fazla yorum var mı? Bu oldukça anlaşılır. Soru, listenin esnekliğinden yaklaşık 3 kez daha hızlı sizin için daha iyi olduğunda. Ama bu başka bir soru. Bu arada, elle oluşturulmuş ArrayList temelinde de kontrol ettim . Hemen hemen aynı sonuç.

5
cevap Roman Nikitchenko 2013-10-24 13:02:12
kaynak

burada zaten çok sayıda iyi cevap olduğundan, size ekleme ve yineleme performansı karşılaştırması olan pratik görünüm hakkında başka bazı bilgiler vermek istiyorum: primitive array vs Linked-list in Java.

bu gerçek basit performans kontrolü.

yani, sonuç makine performansına bağlı olacaktır.

bunun için kullanılan kaynak kodu aşağıda:

import java.util.Iterator;
import java.util.LinkedList;

public class Array_vs_LinkedList {

    private final static int MAX_SIZE = 40000000;

    public static void main(String[] args) {

        LinkedList lList = new LinkedList(); 

        /* insertion performance check */

        long startTime = System.currentTimeMillis();

        for (int i=0; i<MAX_SIZE; i++) {
            lList.add(i);
        }

        long stopTime = System.currentTimeMillis();
        long elapsedTime = stopTime - startTime;
        System.out.println("[Insert]LinkedList insert operation with " + MAX_SIZE + " number of integer elapsed time is " + elapsedTime + " millisecond.");

        int[] arr = new int[MAX_SIZE];

        startTime = System.currentTimeMillis();
        for(int i=0; i<MAX_SIZE; i++){
            arr[i] = i; 
        }

        stopTime = System.currentTimeMillis();
        elapsedTime = stopTime - startTime;
        System.out.println("[Insert]Array Insert operation with " + MAX_SIZE + " number of integer elapsed time is " + elapsedTime + " millisecond.");


        /* iteration performance check */

        startTime = System.currentTimeMillis();

        Iterator itr = lList.iterator();

        while(itr.hasNext()) {
            itr.next();
            // System.out.println("Linked list running : " + itr.next());
        }

        stopTime = System.currentTimeMillis();
        elapsedTime = stopTime - startTime;
        System.out.println("[Loop]LinkedList iteration with " + MAX_SIZE + " number of integer elapsed time is " + elapsedTime + " millisecond.");


        startTime = System.currentTimeMillis();

        int t = 0;
        for (int i=0; i < MAX_SIZE; i++) {
            t = arr[i];
            // System.out.println("array running : " + i);
        }

        stopTime = System.currentTimeMillis();
        elapsedTime = stopTime - startTime;
        System.out.println("[Loop]Array iteration with " + MAX_SIZE + " number of integer elapsed time is " + elapsedTime + " millisecond.");
    }
}

performans sonucu aşağıda:

enter image description here

5
cevap boraseoksoon 2016-12-21 22:10:31
kaynak

bir ArrayList bir dizi kapsüllediğini unutmayın, bu nedenle ilkel bir dizi kullanmaya kıyasla çok az fark vardır (bir listenin Java'da çalışması çok daha kolay olması dışında).

bir diziyi bir Arraylist'e tercih etmenin mantıklı olduğu tek zaman, ilkelleri, yani bayt, int vb.depolarken ve ilkel diziler kullanarak elde ettiğiniz belirli alan verimliliğine ihtiyacınız olduğunda.

4
cevap Nuoji 2009-04-04 15:42:25
kaynak

dizi vs. liste seçimi, dize nesnelerini depolamak durumunda o kadar önemli değildir (performans göz önüne alındığında). Hem dizi hem de liste, gerçek nesneler değil, dize nesne referanslarını depolayacağından.

  1. dizelerin sayısı neredeyse sabitse, bir dizi (veya ArrayList) kullanın. Ancak sayı çok fazla değişirse, Linkedlist'i daha iyi kullanırsınız.
  2. öğeleri ekleme veya silme ihtiyacı varsa (veya olacaksa orta, o zaman kesinlikle LinkedList kullanmanız gerekir.
4
cevap Emre 2009-04-04 18:29:45
kaynak

verilerin ne kadar büyük olduğunu önceden biliyorsanız, bir dizi daha hızlı olacaktır.

bir liste daha esnektir. Bir dizi tarafından desteklenen bir ArrayList kullanabilirsiniz.

3
cevap TofuBeer 2009-04-04 10:00:50
kaynak

listesi dizilerden daha yavaştır.Diziler kullanmanız gerekiyorsa.Listeyi kullanmanız gerekiyorsa.

3
cevap Warrior 2009-04-04 10:04:15
kaynak

sabit bir boyutla yaşayabilirsiniz, diziler daha hızlı olacak ve daha az belleğe ihtiyaç duyacaktır.

liste arabiriminin ekleme ve kaldırma öğeleriyle esnekliğine ihtiyacınız varsa, hangi uygulamayı seçmelisiniz sorusu kalır. Genellikle ArrayList tavsiye edilir ve her durumda kullanılır, ama aynı zamanda ArrayList başında veya listenin ortasında elemanları kaldırıldı veya eklenmelidir eğer performans sorunları vardır.

sen bu nedenle bakmak isteyebilirsiniz http://java.dzone.com/articles/gaplist-%E2%80%93-lightning-fast-list gaplist'i tanıtan . Bu yeni liste uygulaması hemen hemen tüm işlemler için çok iyi bir performans sonuçlanan ArrayList ve LinkedList hem güçlü birleştirir.

3
cevap Thomas Mauch 2012-10-19 15:10:24
kaynak
Uygulamaya bağlı olarak

. bir dizi ilkel türün Arraylist'den daha küçük ve daha verimli olması mümkündür. Bunun nedeni, dizinin değerleri doğrudan bitişik bir bellek bloğunda depolayacağıdır; en basit ArrayList uygulaması her bir değere işaretçiler depolayacaktır. Özellikle 64 bit bir platformda, bu büyük bir fark yaratabilir.

tabii ki, jvm uygulamasının bunun için özel bir davaya sahip olması mümkündür durum, bu durumda performans aynı olacaktır.

2
cevap JRalph 2010-09-11 18:57:15
kaynak

listesi Java 1.5 ve ötesinde jenerikleri kullanabileceği için tercih edilen yoldur. Diziler jenerik olamaz. Ayrıca Diziler dinamik olarak büyüyemeyen önceden tanımlanmış bir uzunluğa sahiptir. Büyük boyutlu bir diziyi başlatmak iyi bir fikir değildir. ArrayList jenerik ile bir dizi bildirmek için yoludur ve dinamik olarak büyüyebilir. Ancak, delete ve ınsert daha sık kullanılıyorsa, bağlantılı liste kullanılacak en hızlı veri yapısıdır.

2
cevap Shehan Simen 2013-12-05 02:54:25
kaynak

Diziler öğeleri sayısı ve boyutu değişmeyeceğini biliyorsanız, özellikle durumunda, liste yerine bunları kullanabilirsiniz her yerde önerilir.

Oracle Java en iyi uygulama bakın: http://docs.oracle.com/cd/A97688_16/generic.903/bp/java.htm#1007056

tabii ki, toplama birçok kez kolay kullanım listeleri nesneleri eklemek ve kaldırmak gerekiyorsa.

2
cevap Nik 2014-02-19 10:37:00
kaynak

ArrayList öğelerini Object[] dizisinde saklar ve yazılan diziden çok daha hızlı (mavi çubuk) olan untyped toArray yöntemini kullanır. Bu typesafe untyped dizi derleyici tarafından denetlenen genel türü ArrayList<T> sarılmış olduğundan.

enter image description here

bu grafik Java 7 üzerinde n = 5 ile bir kriter gösterir. Ancak, resim çok daha fazla öğe veya başka ile değişmez VM. CPU yükü sert görünmeyebilir, ancak ekler. Şans, bir dizinin tüketicilerinin onunla bir şey yapmak için bir koleksiyona dönüştürmesi, ardından sonucu başka bir arabirim yöntemine vb.beslemek için bir diziye geri dönüştürmesi gerektiğidir. Bir dizi yerine basit bir ArrayList kullanarak çok fazla ayak izi eklemeden performansı artırır. ArrayList , sarılmış diziye 32 baytlık sabit bir ek yükü ekler. Örneğin, on nesneli bir array 104 bayt gerektirir, bir ArrayList 136 bayt.

bu işlem sürekli olarak gerçekleştirir, bu nedenle yukarıdaki (sarı çubuk) herhangi birinden çok daha hızlıdır. Bu savunma kopyası ile aynı değildir. İç verileriniz değiştiğinde değiştirilemez bir koleksiyon değişecektir. Bu durumda, istemciler öğeler üzerinde yineleme yaparken ConcurrentModificationException çalıştırabilirsiniz. Bir arabirimin çalışma zamanında UnsupportedOperationException atan yöntemleri sağladığı kötü tasarım olarak kabul edilebilir. Bununla birlikte, en azından iç kullanım için, bu yöntem, bir defansif kopyaya yüksek performanslı bir alternatif olabilir-dizilerle mümkün olmayan bir şey.

2
cevap Show Stopper 2015-11-20 19:28:16
kaynak

cevapların hiçbiri ilgimi çeken bilgilere sahip değildi-aynı dizinin tekrar eden taraması birçok kez. Bunun için bir JMH testi oluşturmak zorunda kaldım.

sonuçları (Java 1.8.0_66 x32, yineleme düz dizi ArrayList en az 5 kat daha hızlı):

Benchmark                    Mode  Cnt   Score   Error  Units
MyBenchmark.testArrayForGet  avgt   10   8.121 ? 0.233  ms/op
MyBenchmark.testListForGet   avgt   10  37.416 ? 0.094  ms/op
MyBenchmark.testListForEach  avgt   10  75.674 ? 1.897  ms/op

Test

package my.jmh.test;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;
import org.openjdk.jmh.annotations.Benchmark;
import org.openjdk.jmh.annotations.BenchmarkMode;
import org.openjdk.jmh.annotations.Fork;
import org.openjdk.jmh.annotations.Measurement;
import org.openjdk.jmh.annotations.Mode;
import org.openjdk.jmh.annotations.OutputTimeUnit;
import org.openjdk.jmh.annotations.Scope;
import org.openjdk.jmh.annotations.State;
import org.openjdk.jmh.annotations.Warmup;

@State(Scope.Benchmark)
@Fork(1)
@Warmup(iterations = 5, timeUnit = TimeUnit.SECONDS)
@Measurement(iterations = 10)
@BenchmarkMode(Mode.AverageTime)
@OutputTimeUnit(TimeUnit.MILLISECONDS)
public class MyBenchmark {

    public final static int ARR_SIZE = 100;
    public final static int ITER_COUNT = 100000;

    String arr[] = new String[ARR_SIZE];
    List<String> list = new ArrayList<>(ARR_SIZE);

    public MyBenchmark() {
        for( int i = 0; i < ARR_SIZE; i++ ) {
            list.add(null);
        }
    }

    @Benchmark
    public void testListForEach() {
        int count = 0;
        for( int i = 0; i < ITER_COUNT; i++ ) {
            for( String str : list ) {
                if( str != null )
                    count++;
            }
        }
        if( count > 0 )
            System.out.print(count);
    }

    @Benchmark
    public void testListForGet() {
        int count = 0;
        for( int i = 0; i < ITER_COUNT; i++ ) {
            for( int j = 0; j < ARR_SIZE; j++ ) {
                if( list.get(j) != null )
                    count++;
            }
        }
        if( count > 0 )
            System.out.print(count);
    }

    @Benchmark
    public void testArrayForGet() {
        int count = 0;
        for( int i = 0; i < ITER_COUNT; i++ ) {
            for( int j = 0; j < ARR_SIZE; j++ ) {
                if( arr[j] != null )
                    count++;
            }
        }
        if( count > 0 )
            System.out.print(count);
    }

}
2
cevap Xtra Coder 2016-06-01 23:00:14
kaynak

"binlerce" çok sayıda değil. Birkaç bin paragraf uzunluğundaki dizeler, birkaç megabayt büyüklüğünde sıradadır. Eğer yapmak istediğiniz tüm bu seri erişim, bağlantılı Liste '151920920 151910920' değişmez bir tek-'seçeneğini kullanın .

2
cevap Apocalisp 2016-06-10 19:59:45
kaynak

uygun kıyaslama olmadan optimize etme tuzağına girmeyin. Diğerlerinin önerdiği gibi, herhangi bir varsayım yapmadan önce bir profiler kullanın.

numaralandırdığınız farklı veri yapılarının farklı amaçları vardır. Bir liste başında ve sonunda öğeleri ekleme çok etkilidir ama rastgele öğeleri erişirken çok acı. Bir dizi sabit depolama alanına sahiptir, ancak hızlı rastgele erişim sağlar. Son olarak, bir ArrayList bir arayüz geliştirir büyümeye izin vererek dizi. Normalde kullanılacak veri yapısı, depolanan verilerin nasıl erişileceği veya ekleneceği ile belirlenmelidir.

bellek tüketimi hakkında. Bazı şeyleri karıştırıyor gibisin. Bir dizi, yalnızca sahip olduğunuz veri türü için sürekli bir bellek yığını verecektir. Java'nın sabit bir veri türü olduğunu unutmayın: boolean, char, int, long, float ve Object (bu, tüm nesneleri içerir, hatta bir dizi bir nesnedir). Bu, bir beyan ederseniz dize dizeleri dizisi [1000] veya MyObject myObjects [1000] yalnızca nesnelerin yerini (referansları veya işaretçileri) depolayacak kadar büyük bir 1000 bellek kutusu alırsınız. Nesnelerin büyüklüğüne uyacak kadar büyük bir 1000 bellek kutusu almazsınız. Nesnelerinizin ilk önce "yeni"ile oluşturulduğunu unutmayın. Bu, bellek tahsisi yapıldığında ve daha sonra bir başvuru (bellek adresi) dizide saklanır. Nesne diziye yalnızca referans olarak kopyalanmaz.

1
cevap potyl 2009-04-04 10:39:46
kaynak

dizeler için gerçek bir fark yarattığını sanmıyorum. Bir dizi dizede bitişik olan, dizelere yapılan referanslar, dizelerin kendileri bellekte rastgele yerlerde saklanır.

diziler ve listeler, nesneler için değil, ilkel türler için bir fark yaratabilir. eğer öğelerin sayısını önceden biliyorsanız ve esnekliğe ihtiyacınız yoksa, milyonlarca tamsayıya veya iki katına sahip bir dizi bellekte daha verimli olacaktır ve marjinal olarak bir listeden daha hızlıdır, çünkü gerçekten de bitişik olarak saklanır ve anında erişilir. Bu nedenle Java hala dizeler için karakter dizilerini, görüntü verileri için int dizilerini vb. kullanır.

1
cevap PhiLho 2009-04-04 12:49:47
kaynak

dizisi daha hızlıdır-tüm bellek önceden tahsis edilmiştir.

1
cevap Yakov Fain 2009-04-04 18:35:12
kaynak

burada verilen çok sayıda mikrobenchmarks, array/ArrayList reads gibi şeyler için birkaç nanosaniye buldu. Her şey L1 önbelleğinizde ise bu oldukça makul.

daha üst düzey bir önbellek veya ana bellek erişimi, L1 önbelleği için daha fazla 1nS gibi 10ns-100nS gibi bir şeyin büyüklük süreleri sırasına sahip olabilir. Bir ArrayList erişme ekstra bir bellek indirection vardır, ve gerçek bir uygulamada neredeyse hiç bu maliyeti her şey ödeyebilirsiniz zaman, kodunuzun erişimler arasında ne yaptığına bağlı olarak. Ve tabii ki, eğer bir sürü küçük Arraylistiniz varsa, bu bellek kullanımınıza ekleyebilir ve önbellek özlüyor olmanız daha olası hale getirebilir.

orijinal poster sadece bir tane kullanıyor ve kısa sürede çok fazla içeriğe erişiyor gibi görünüyor, bu yüzden büyük bir sıkıntı olmamalı. Ama diğer insanlar için farklı olabilir ve microbenchmarks yorumlarken dikkat etmelisiniz.

Java Bununla birlikte, dizeler, özellikle de çok sayıda küçük olanı saklarsanız (yalnızca bir bellek analizörü ile onlara bakarsanız, birkaç karakter dizisi için > 60 bayt gibi görünüyor), inanılmaz derecede boşa gider. Dizelerin bir dizi dize nesnesi ve dize nesnesinden dize kendisini içeren bir char[] için bir indirection vardır. L1 önbelleğini patlatacak bir şey varsa, bu, binlerce veya on binlerce Dizeyle birleştirildi. Yani, eğer ciddi iseniz - gerçekten ciddi - kazıma hakkında mümkün olduğunca fazla performans gösterdikten sonra farklı bir şekilde yapmaya bakabilirsiniz. Diyelim ki, iki diziyi, içindeki tüm dizelerle, birbiri ardına bir char[] ve başlangıçlara uzak olan bir int[] tutabilirsiniz. Bir şey düzgün çalışmıyor ve ne olduğundan emin değiliz. Ve bunu yaparsanız, yanlış dili seçtiniz.

1
cevap Alex Hayward 2014-10-31 12:59:34
kaynak

diziler üzerindeki listeleri kullanmanın performans etkisi için daha iyi bir his elde etmek için buraya geldim. Senaryom için kodu burada uyarlamak zorunda kaldım: array / list of ~ 1000 ints çoğunlukla getters kullanarak, array[j] vs. list anlamına gelir.almak (j)

7'nin en iyisini alarak bu konuda bilimsel olmayan (2.5 x daha yavaş olan ilk birkaç liste) bunu alıyorum:

array Integer[] best 643ms iterator
ArrayList<Integer> best 1014ms iterator

array Integer[] best 635ms getter
ArrayList<Integer> best 891ms getter (strange though)

- bu nedenle,

dizisiyle kabaca %30 daha hızlı

gönderme ikinci nedeni şimdi, iç içe döngüleriyle matematik/matris/simülasyon/optimizasyon kodu yaparsanız hiç kimse etkiden bahsetmiyor.

, üç iç içe geçmiş seviyeniz olduğunu ve iç döngü, 8 kez performans vuruşuna baktığınız iki kat daha yavaş olduğunu söylüyor. Bir gün içinde çalışacak bir şey artık bir hafta sürer.

* Düzenle Burada oldukça şok oldum, tekmeler için Integer[1000] yerine Integer[1000]

ilan etmeyi denedim
array int[] best 299ms iterator
array int[] best 296ms getter

kullanma Integer [] vs. int [] bir çift performans hit temsil eder, yineleyici ile ListArray int [] daha yavaş 3x olduğunu. Java'nın liste uygulamalarının yerli dizilere benzediğini gerçekten düşündüm...

referans kodu (birden çok kez arayın):

    public static void testArray()
    {
        final long MAX_ITERATIONS = 1000000;
        final int MAX_LENGTH = 1000;

        Random r = new Random();

        //Integer[] array = new Integer[MAX_LENGTH];
        int[] array = new int[MAX_LENGTH];

        List<Integer> list = new ArrayList<Integer>()
        {{
            for (int i = 0; i < MAX_LENGTH; ++i)
            {
                int val = r.nextInt();
                add(val);
                array[i] = val;
            }
        }};

        long start = System.currentTimeMillis();
        int test_sum = 0;
        for (int i = 0; i < MAX_ITERATIONS; ++i)
        {
//          for (int e : array)
//          for (int e : list)          
            for (int j = 0; j < MAX_LENGTH; ++j)
            {
                int e = array[j];
//              int e = list.get(j);
                test_sum += e;
            }
        }

        long stop = System.currentTimeMillis();

        long ms = (stop - start);
        System.out.println("Time: " + ms);
    }
1
cevap Xult 2018-07-03 17:13:50
kaynak

erişmek zorunda nasıl bağlıdır.

depoladıktan sonra, esas olarak arama işlemi yapmak istiyorsanız, az veya hiç ekleme/silme ile, dizilerde o (1) ' de arama yapıldığı için diziye gidin, oysa ekleme / silme öğelerin yeniden sıralanmasına ihtiyaç duyabilir).

Depoladıktan sonra, ana Amacınız dizeleri eklemek/silmek ise, az veya hiç arama işlemi yapılmazsa, listeye gidin.

0
cevap Vikram 2012-07-26 01:53:41
kaynak

ArrayList DAHİLİ olarak array nesne eklemek(veya depolamak) kullanır öğeler. Başka bir deyişle, ArrayList dizi verileri tarafından desteklenmektedir -yapılı.ArrayList dizisi yeniden boyutlandırılabilir (veya dinamik).

dizisi diziden daha hızlıdır çünkü ArrayList diziyi DAHİLİ olarak kullanır. doğrudan Array öğeleri ekleyebilir ve dolaylı olarak öğe ekleyebilirsek ArrayList aracılığıyla dizi her zaman doğrudan mekanizma daha hızlıdır dolaylı mekanizma.

ArrayList sınıfında iki aşırı yüklenmiş add() yöntemi vardır:

1. add(Object) : listenin sonuna nesne ekler.

2. add(int index , Object ) : belirtilen nesneyi listede belirtilen konuma ekler.

ArrayList boyutu dinamik olarak nasıl büyür?

public boolean add(E e)        
{       
     ensureCapacity(size+1);
     elementData[size++] = e;         
     return true;
}

yukarıdaki koddan dikkat edilmesi gereken önemli nokta öğeyi eklemeden önce ArrayList kapasitesini kontrol ediyoruz. ensureCapacity (), işgal edilen öğelerin geçerli boyutunun ne olduğunu ve dizinin maksimum boyutunun ne olduğunu belirler. Doldurulmuş öğelerin boyutu (eklenecek yeni öğe de dahil olmak üzere ArrayList sınıfı) dizinin maksimum boyutundan büyükse, dizinin boyutunu artırın. Ancak dizinin boyutu dinamik olarak artırılamaz. Yani DAHİLİ olarak ne olur yeni dizi kapasitesi ile oluşturulur

- Java 6

int newCapacity = (oldCapacity * 3)/2 + 1;

(Güncelleme) Java 7

 int newCapacity = oldCapacity + (oldCapacity >> 1);

ayrıca, eski diziden gelen veriler yeni diziye kopyalanır.

arraylist'te havai yöntemlere sahip olmak, bu nedenle Array ArrayList dan daha hızlıdır .

0
cevap Vipin Jain 2016-02-22 09:24:49
kaynak