En verimli Java Collections kitaplığı nedir? [kapalı]


135

En verimli Java Collections kitaplığı nedir?

Birkaç yıl önce, Java yaptım ve o zamanlar izlenimi vardı hazinesi iyi (en verimli) Java Koleksiyonları uygulamasıdır. Ben sorusuna cevap okurken Ama " En yararlı ücretsiz Java kütüphaneleri? " Fark ettim hazinesi pek söz edilmektedir. Peki şu anda hangi Java Koleksiyonlar kütüphanesi en iyisidir?

GÜNCELLEME: Açıklığa kavuşturmak için, çoğunlukla bir karma tabloda vb. Milyonlarca girişi depolamak zorunda kaldığımda hangi kütüphanenin kullanılacağını bilmek istiyorum.


Bu tablodaki anahtarlar ve değerler nelerdir? İlkel değillerse normal HashMap vb. İle ilgili sorun nedir?
Jon Skeet

Çok büyük bir harita için, bir problama uygulaması isteyebilirsiniz, hatta bir veritabanı tablosu gibi hizalanabilir.
Tom Hawtin - taktik çizgisi

1
İlginçtir ben burada Colt daha sonra Mahout içine toplanan hiçbir söz görmüyorum.
smartnut007

4
Çok güzel bir koleksiyon kütüphanesi - GS koleksiyonlarından (github.com/goldmansachs/gs-collections) bahsetmeye değer. Mükemmel belgelere ve kapsamlı bir değişken ve değişmez
koleksiyonlara sahiptir

Yanıtlar:


73

İncelemeden, Trove sadece ilkel tipler için bir koleksiyon kütüphanesi gibi görünüyor - JDK'daki normal koleksiyonlara çok fazla işlevsellik eklemek gibi bir şey değil.

Şahsen (ve önyargılıyım) Guava'yı seviyorum (eski Google Java Koleksiyonları projesi dahil). Çeşitli görevleri (koleksiyonlar dahil) en azından makul derecede verimli bir şekilde çok daha kolay hale getirir. Tahsilat işlemleri nadiren benim kodumda (benim deneyimime göre) bir darboğaz oluşturduğu göz önüne alındığında, bu daha verimli olabilir ama kodumu okunabilir yapmaz bir koleksiyon API daha "iyi".

Trove ve Guava arasındaki örtüşmenin neredeyse sıfır olduğu göz önüne alındığında, belki de bir koleksiyon kütüphanesinden gerçekten aradığınızı netleştirebilirsiniz.


3
@Andreas: Kabul ettiğimi söyleyemem. Bu "bir ya da diğer" bir senaryo değil - düzenli koleksiyonlar (Lists sınıfı gibi yardımcıları ile) kullanın ve sonra gerektiğinde Iterables vb kullanın. Karmaşıklığı yalnızca size yardımcı olduğunda kullanın.
Jon Skeet

10
GC'yi kapsamlı bir şekilde kullandıktan birkaç ay sonra kendi yorumumu okuduktan sonra - geçmiş düşünceme katılmıyorum ve sizinkine tamamen katılıyorum. yardımcı yöntemleri / sınıfları yaygın olarak kullanırlar, kodun çoğunu daha okunaklı ve güvenli hale getirir.
Andreas Petersson

1
@Andreas: Geri gelip söylediğin için teşekkürler - GJC'nin yardımcı olduğunu duyduğuma sevindim :)
Jon Skeet

2
Hey, Jon, Google Java Collections artık Guava . Yayınınızı gelecekteki referanslarınız için güncellemek isteyebilirsiniz :)
Artur Czajka

1
Koleksiyonların büyük bir darboğaz olduğu birkaç veri yoğun projede çalıştım. Java Koleksiyonlar, özellikle ilkelleri depolarlarsa (hem bellek hem de hız) çok verimsizdir.
Jay Askren

104

Soru (şimdi) int, bir Harita gibi ilkel türler kullanılarak temsil edilebilecek çok sayıda veri depolamakla ilgilidir . Buradaki cevapların bazıları bence çok yanıltıcı. Bakalım neden.

Hem çalışma zamanını hem de bellek tüketimini ölçmek için ölçütü trove'dan değiştirdim . İlkel tipler için başka bir koleksiyon kütüphanesi olan bu karşılaştırmaya PCJ ekledim (bunu yoğun olarak kullanıyorum). 'Resmi' trove kıyaslaması IntIntMaps'i Java Collection'larla karşılaştırmaz Map<Integer, Integer>, muhtemelen depolama Integersve depolama intsteknik açıdan aynı değildir. Ancak bir kullanıcı bu teknik ayrıntıyı önemsemeyebilir, intsverimli bir şekilde temsil edilebilen verileri saklamak ister .

Önce kodun ilgili kısmı:

new Operation() {

     private long usedMem() {
        System.gc();
        return Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory();
     }

     // trove
     public void ours() {
        long mem = usedMem();
        TIntIntHashMap ours = new TIntIntHashMap(SET_SIZE);
        for ( int i = dataset.size(); i-- > 0; ) {
           ours.put(i, i);
        }
        mem = usedMem() - mem;
        System.err.println("trove " + mem + " bytes");
        ours.clear();
     }

     public void pcj() {
        long mem = usedMem();
        IntKeyIntMap map = new IntKeyIntOpenHashMap(SET_SIZE);
        for ( int i = dataset.size(); i-- > 0; ) {
           map.put(i, i);
        }
        mem = usedMem() - mem;
        System.err.println("pcj " + mem + " bytes");
        map.clear();
     }

     // java collections
     public void theirs() {
        long mem = usedMem();
        Map<Integer, Integer> map = new HashMap<Integer, Integer>(SET_SIZE);
        for ( int i = dataset.size(); i-- > 0; ) {
           map.put(i, i);
        }
        mem = usedMem() - mem;
        System.err.println("java " + mem + " bytes");
        map.clear();
     }

Verilerin ilkel olduğunu düşünüyorum ints , aklı başında gibi görünüyor. Ancak bu, ilkel koleksiyon çerçeveleri için gerekli olmayan otomatik boks nedeniyle java util için bir çalışma zamanı cezası anlamına gelir.

gc()WinXP, jdk1.6.0_10'da çalışma zamanı sonuçları ( elbette çağrılar olmadan ):

                      100000 koyma işlemleri 100000 işlemler içerir 
java koleksiyonları 1938 ms 203 ms
bölme 234 ms 125 ms
pcj 516 ms 94 ms

Bu zaten ciddi gibi görünse de, böyle bir çerçeveyi kullanmanın nedeni bu değildir.

Nedeni bellek performansıdır. 100000 içeren bir Harita için sonuçlarint giriş :

java koleksiyonları 6644536 ve 7168840 bayt arasında dalgalanır
trove 1853296 bayt
pcj 1866112 bayt

Java Collections , ilkel koleksiyon çerçevelerine kıyasla belleğin üç katından fazlasına ihtiyaç duyar . Yani, çalışma zamanı performansını büyüklüklerle azaltan disk IO'ya başvurmadan bellekte üç kat daha fazla veri tutabilirsiniz. Ve bu önemli. Nedenini bulmak için yüksek ölçeklenebilirliği okuyun .

Deneyimlerime göre, yüksek bellek tüketimi Java ile ilgili en büyük performans sorunudur, bu da elbette daha kötü çalışma zamanı performansı ile sonuçlanır. İlkel koleksiyon çerçeveleri gerçekten yardımcı olabilir.

Yani: Hayır, java.util cevap değil. Ve Java koleksiyonlarına "işlevsellik katmak" verimlilik sorulduğunda önemli değildir. Ayrıca, modern JDK koleksiyonları yapmak değil "bile uzman Olimpiyatı koleksiyonları gerçekleştirmek dışı".

Feragatname: Buradaki kıyaslama tam olmaktan uzak değildir ve mükemmel değildir. Bu, birçok projede yaşadığım noktayı eve götürmek içindir. İlkel koleksiyonları balık API tolere kullanışlı yeterli - eğer sen birçok bilgiye sahip olan çalışırlar.


3
Aslında cevabınızın yanıltıcı olduğunu düşünüyorum. Ints ve Integers karşılaştırması çok farklıdır ve büyük olasılıkla artan bellek kullanımının ana sebebidir. Ham tür toplama çerçevesinin yararlı olabileceğini kabul ediyorum, ancak trove veya pcj'yi java.util'den "daha iyi" yapmıyor.
Jorn

22
Soru, int verilerinin verimli bir şekilde saklanması ile ilgilidir. Tamsayıları saklamakla ilgili değil. Bu görev için göstermeye çalıştığım gibi trove / pcj daha verimlidir. Tamsayıların kullanılması, çalışma zamanı ve bellek verimsizlikleri sağlar. Java.util ilkellerin kullanılmasına izin vermediğinden, bu görev için en iyi seçim değildir.
the.duckman

2
(Rus toplumu için) burada başka bir kriter daha var: total-holywar.blogspot.com/2011/07/…
dma_k

İnt anahtar olarak kullanılmıyor mu emin değilim, sadece normal String. Onlar için çalışma tezgahı sonucu ne olacak?
Clark Bao

@ClarkBao (geç kaldığım için üzgünüm) Herhangi bir nesneyi anahtar olarak saklamak nesneyi kullanacaktır hashCode(). Seni intanahtar olarak alır .
Matthieu

47

Bunun eski bir yazı olduğunu biliyorum ve burada bir ton cevap var. Ancak, yukarıdaki cevaplar yüzeysel ve bir kütüphane önermek için aşırı basitleştirilmiştir. Burada sunulan çeşitli ölçütlerde iyi performans gösteren tek bir kütüphane yoktur. Elde ettiğim tek sonuç performans ve bellek ve özellikle ilkel tiplerle ilgileniyorsanız, jdk olmayan alternatiflere bakmaya değer.

Kıyaslama mekaniği ve kapsanan kütüphaneler açısından daha sağlam bir analiz. Bu , posta geliştirme listesindeki bir iş parçacığıdır.

Kapsanan kütüphaneler

  • HPPC
  • define
  • FastUtil
  • Mahir (Colt)
  • Java Koleksiyonları

Haziran 2015 Güncellemesi : Ne yazık ki, orijinal kriterler artık mevcut değil ve bunun yanı sıra biraz modası geçmiş. İşte başkası tarafından yapılan oldukça yeni (Ocak 2015) kriterleri. Orijinal bağlantı kadar interaktif keşif araçlarına da sahip değildir.


1
Teşekkür ederim. Bu çok yardımcı oldu. Sorunun önemi göz önüne alındığında, diğer cevapların (duckman'ın dışında) hiçbirinin aslında bu soruya cevap verdiğine inanmak zor.
Dexter

20

Diğer yorumcuların fark ettiği gibi, "verimli" tanımı geniş bir ağ oluşturur. Ancak henüz hiç kimse Javolution kütüphanesinden bahsetmedi .

Öne çıkanlardan bazıları:

  • Javolution sınıfları hızlı, çok hızlıdır (örneğin, standart StringBuffer / StringBuilder için O [n] yerine O [Günlük (n)] içine metin ekleme / silme).
  • Tüm Javolution sınıfları gerçek zamanlı olarak zordur ve yüksek derecede deterministik davranışa sahiptir (mikrosaniye aralığında). Ayrıca (standart kütüphaneden farklı olarak) Javolution RTSJ güvenlidir (Java Real-Time uzantısı ile kullanıldığında bellek çakışması veya bellek sızıntısı olmaz).
  • Javolution'ın gerçek zamanlı koleksiyon sınıfları (harita, liste, tablo ve küme) çoğu standart koleksiyon sınıfının yerine kullanılabilir ve ek işlevsellik sağlar.
  • Javolution koleksiyonları, paralel algoritmaların uygulanmasını kolaylaştırmak için eşzamanlılık garantisi sağlar.

Javolution dağıtımı, diğer kütüphanelere / yerleşik koleksiyonlara karşı nasıl yığınlandıklarını görebilmeniz için bir karşılaştırma paketi içerir.


16

Dikkate alınması gereken bazı koleksiyon kütüphaneleri:

JDK koleksiyon kütüphanesine her şeyden önce ulaşırdım. Yapmanız gereken en yaygın şeyleri kapsar ve sizin için zaten açıktır.

Google Koleksiyonlar muhtemelen JDK dışındaki en iyi yüksek kaliteli kütüphanedir. Çok kullanılır ve iyi desteklenir.

Apache Commons Collections daha eskidir ve "çok fazla aşçı" probleminden biraz muzdariptir, ancak birçok yararlı şey de vardır.

Trove, ilkel anahtarlar / değerler gibi durumlar için çok özel koleksiyonlara sahiptir. Günümüzde modern JDK'larda ve Java 5+ koleksiyonları ve eşzamanlı kullanım durumlarında JDK koleksiyonlarının özel Trove koleksiyonlarını bile gerçekleştirdiğini görüyoruz.

Gerçekten yüksek eşzamanlılık kullanım durumlarınız varsa, kilitsiz bir uygulama olan ve bunun için doğru kullanım durumunuz varsa ConcurrentHashMap üzerinde durabilen yüksek ölçekli lib'deki NonBlockingHashMap gibi şeyleri kesinlikle kontrol etmelisiniz.


7
"Bu günlerde modern JDK'larda ve Java 5+ koleksiyonları ve eşzamanlı kullanım durumlarında JDK koleksiyonlarının özel Trove koleksiyonlarını bile gerçekleştirdiğini görüyoruz." Yanıltıcı - Trove gibi özel bir ilkel toplama sınıfında ilkel türlerin depolanmasının / alınmasının, bellek kullanımı ve CPU zamanında JDK toplama sınıflarından daha iyi performans göstermediği bir mikro ölçüt hiç görmedim. Nesneleri olsa da (ilkel türler değil) kullanıyorsanız, Alex ile aynı fikirde olurdum, koleksiyon impl üzerinde üzülmek bir anlaşma kadar büyük değildir.
Riyad Kalla

2
Bu ifade, daha önce bir Trove koleksiyonuna ihtiyaç duyduğumuz, ancak şimdi çıkarabildiğimiz çeşitli toplama impls'larının ağır gerçek dünya kullanımına dayanıyordu (her gün bir mikro karşılaştırmayı ele alacağım). Geç JDK 6 güncellemeleri (2009'un sonlarına doğru), Integer gibi yaygın harita anahtarları için en yaygın kullanımlardan bazılarını önemli ölçüde iyileştiren özel kod sağladı.
Alex Miller

1
Alex, özel kullanım durumlarınızda, ilkel koleksiyonları çıkarmanın ve JDK koleksiyonlarıyla gitmenin yeterince hızlı olduğundan şüphelenmiyorum, ancak elinizi koleksiyonlar olan manzaraya sallamak ve "Hepiniz geçiyorsunuz, yeterince hızlı! " doğru değil. Bir 2D oyun motoru üzerinde çalışıyorsam, ilkel tiplerimi boks / kutudan çıkarma yükü sürekli olarak pahalıdır. Bir REST API üzerinde çalışıyorsam, hayır, muhtemelen HTTP I / O gibi çok daha pahalı ops açısından ölçülebilir bir farklı yapmaz. Sadece gönderinizi ölçmek zorunda kaldım.
Riyad Kalla

4
Bunu okuyan kimsenin ikimizi de dinlemesi gerektiğini düşünmüyorum. Kendi kullanım durumlarını test etmeli ve neyin en iyi performans gösterdiğini görmelidirler. Yorumlarım, ekibimin çeşitli kütüphanelerle oldukça agresif performans testlerine dayanıyor. YMMV.
Alex Miller

2
@Riyad'a katılıyorum. Yüksek performanslı bir sonlu otomata paketi yazıyorum ve hem Trove hem de Java Collections Framework (jdk 6 son güncelleme) ile uyguladım. Trove büyük zamandan daha iyi performans gösteriyor. Hem hesaplama hızı hem de bellek tüketiminde onlarca kez daha iyi.
Nico Huysamen

6

java.util

Açık cevap için özür dilerim, ancak çoğu kullanım için varsayılan Java Koleksiyonları yeterlidir.


4
Temel kullanımlar için evet. Ancak, çerçevenin bazı temel ve gelişmiş özellikleri (değiştirilemez koleksiyonlar, filtreler, çoklu haritalar vb.) Özlediğini düşünüyorum ve burası (örneğin) Google Koleksiyonlarının geldiği yer
Jorn

1
Bence bu cevap noktayı kaçırıyor. JCF muhtemelen insanların çok fazla Java kullanmadığı 2002 yılında harikaydı. Ne yazık ki, özellikle diğer JVM dillerinden gelen koleksiyon desteği ile karşılaştırıldığında iyi yaşlanmadı.
Ted Pennings

3
-1 soru "int depolamak için en verimli" ve bahsedilen herhangi bir örnek java.util
kommradHomer



3

java.util.concurrentHashMap'ı birden çok iş parçacığında kullanmayı planlıyorsanız, ConcurrentHashMap ve paketten bahsedilmelidir. Bu, standart java'nın bir parçası olduğu için küçük bellek alanı elde edilir.


3

Nasıl "verimli" tanımladığımıza bağlıdır.

Her veri yapısının okuma, yazma, yineleme, bellek alanı vb. İçin kendi Big-Oh davranışı vardır. Bir kitaplıktaki bağlantılı listenin diğer kitaplarla aynı olması muhtemeldir. Bir karma haritası O (1) okumak için bağlantılı bir O (n) listesinden daha hızlı olacaktır.

Ama "En kullanışlı ücretsiz Java kütüphaneleri?" Sorusunun cevaplarını okuduğumda. Trove'dan pek bahsedilmediğini fark ettim.

Bu "en verimli" gibi görünmüyor. Bana "en popüler" gibi geliyor.

Sadece bir geri bildirim - Daha önce hiç duymadım ve onu kullanan kimseyi tanımıyorum. JDK, Google veya Apache Commons'ta yerleşik koleksiyonlar benim için iyi biliniyor.


3

Trove birkaç avantaj sunuyor.

  • daha az bellek alanı, Map.Entry nesnelerini kullanmaz
  • haritalar için anahtarlar yerine karma stratejileri kullanabilirsiniz, bu da bellek tasarrufu sağlar ve bir nesneyi yeni bir öznitelikler kümesinde her önbelleğe almak istediğinizde yeni bir anahtar tanımlamanız gerekmediği anlamına gelir
  • ilkel koleksiyon türlerine sahiptir
  • bir çeşit dahili yineleyici olduğunu düşünüyorum

Bununla birlikte, trove yazıldığından beri jdk koleksiyonlarını iyileştirmek için çok şey yapıldı.

Gerçi bana cazip gelen karma stratejiler ... Trove ve genel bakışlarını okumak için Google.


2

Bir karma tabloda milyonlarca kayıt saklamak istiyorsanız, bellek sorunlarıyla karşılaşma olasılığınız yüksektir. Örneğin, 2,3 milyon String nesnesiyle bir harita oluşturmaya çalıştığımda bu bana oldu. Çok olgun olan ve iyi performans gösteren BerkeleyDB ile gittim . Koleksiyonlar API'sini saran bir Java API'sine sahiptir, böylece çok az bellek kaplamasıyla kolayca büyük haritalar oluşturabilirsiniz. Erişim daha yavaş olacaktır (diskte depolandığı için).

Takip eden soru : değişmez koleksiyonlar için iyi (ve verimli), bakımlı bir kütüphane var mı? Clojure bunun için mükemmel bir desteğe sahiptir ve Java için benzer bir şeye sahip olmak güzel olurdu.


1
Google koleksiyonları değişmez Koleksiyonlar ekler.
the.duckman
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.