Thư viện Bộ sưu tập Java hiệu quả nhất là gì? [đóng cửa]


135

Thư viện Bộ sưu tập Java hiệu quả nhất là gì?

Một vài năm trước, tôi đã làm rất nhiều Java và có ấn tượng trở lại sau đó trove đó là triển khai Bộ sưu tập Java tốt nhất (hiệu quả nhất). Nhưng khi tôi đọc câu trả lời cho câu hỏi " Các thư viện Java miễn phí hữu ích nhất? " Tôi nhận thấy rằng trove hầu như không được đề cập. Vì vậy, thư viện Bộ sưu tập Java nào là tốt nhất bây giờ?

CẬP NHẬT: Để làm rõ, tôi chủ yếu muốn biết nên sử dụng thư viện nào khi tôi phải lưu trữ hàng triệu mục trong bảng băm, v.v. (cần một thời gian chạy nhỏ và dấu chân bộ nhớ).


Các khóa và giá trị trong bảng này là gì? Nếu chúng không phải là nguyên thủy, có gì sai với HashMap bình thường, v.v.?
Jon Skeet

Đối với một bản đồ rất lớn, bạn có thể muốn triển khai thăm dò hoặc thậm chí được nội tuyến như bảng cơ sở dữ liệu.
Tom Hawtin - tackline

1
Điều thú vị là tôi không thấy đề cập đến Colt ở đây mà sau đó đã được đưa vào Mahout.
smartnut007

4
Điều đáng nói là thư viện bộ sưu tập rất hay - Bộ sưu tập GS (github.com/goldmansachs/gs-collections). Nó có tài liệu tuyệt vời và một tập hợp đầy đủ các thuộc địa có thể thay đổi và bất biến
Piotr Kochański

Câu trả lời:


73

Từ kiểm tra, có vẻ như Trove chỉ là một thư viện các bộ sưu tập cho các kiểu nguyên thủy - không có nghĩa là nó có thêm nhiều chức năng so với các bộ sưu tập bình thường trong JDK.

Cá nhân (và tôi thiên vị) Tôi yêu Guava (bao gồm cả dự án Bộ sưu tập Java trước đây của Google). Nó làm cho các tác vụ khác nhau (bao gồm cả các bộ sưu tập) dễ dàng hơn rất nhiều, theo cách ít nhất là hiệu quả hợp lý. Do các hoạt động thu thập hiếm khi hình thành nút cổ chai trong mã của tôi (theo kinh nghiệm của tôi), điều này "tốt hơn" so với API bộ sưu tập có thể hiệu quả hơn nhưng không làm cho mã của tôi có thể đọc được.

Cho rằng sự chồng chéo giữa Trove và Guava gần như không, có lẽ bạn có thể làm rõ những gì bạn thực sự tìm kiếm từ một thư viện bộ sưu tập.


3
@Andreas: Không thể nói tôi đồng ý. Không phải đó là kịch bản "cái này hay cái kia" - tôi sử dụng các bộ sưu tập thông thường (với những người trợ giúp như lớp Lists) và sau đó sử dụng Iterables, v.v. khi tôi cần. Chỉ sử dụng sự phức tạp khi nó giúp bạn.
Jon Skeet

10
sau khi đọc bình luận của riêng tôi vài tháng sau khi sử dụng rộng rãi GC - tôi không đồng ý với ý kiến ​​trong quá khứ của tôi và hoàn toàn đồng ý với ý kiến ​​của bạn. sử dụng rộng rãi các phương thức / lớp trợ giúp, chúng làm cho nhiều mã dễ đọc hơn và an toàn hơn.
Andreas Petersson

1
@Andreas: Cảm ơn bạn đã quay lại và nói như vậy - Tôi rất vui khi biết rằng GJC đang giúp đỡ :)
Jon Skeet

2
Này, Jon, Bộ sưu tập Java của Google giờ là Guava . Bạn có thể muốn cập nhật bài viết của mình để tham khảo trong tương lai :)
Artur Czajka

1
Tôi đã làm việc trên một vài dự án chuyên sâu về dữ liệu trong đó các bộ sưu tập là một nút cổ chai lớn. Bộ sưu tập Java rất kém hiệu quả (cả bộ nhớ và tốc độ) đặc biệt nếu chúng lưu trữ nguyên thủy.
Jay Askren

104

Câu hỏi là (bây giờ) về việc lưu trữ nhiều dữ liệu, có thể được biểu diễn bằng các kiểu nguyên thủy như inttrong Bản đồ. Một số câu trả lời ở đây rất sai lệch theo ý kiến ​​của tôi. Hãy xem tại sao.

Tôi đã sửa đổi điểm chuẩn từ trove để đo cả thời gian chạy và mức tiêu thụ bộ nhớ. Tôi cũng đã thêm PCJ vào điểm chuẩn này, đây là một thư viện bộ sưu tập khác cho các kiểu nguyên thủy (tôi sử dụng rộng rãi loại đó). Điểm chuẩn của 'chính thức' không so sánh IntIntMaps với Java Collection Map<Integer, Integer>, có lẽ việc lưu trữ Integersvà lưu trữ intskhông giống nhau theo quan điểm kỹ thuật. Nhưng một người dùng có thể không quan tâm đến chi tiết kỹ thuật này, anh ta muốn lưu trữ dữ liệu có thể biểu diễn một intscách hiệu quả.

Đầu tiên là phần có liên quan của mã:

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();
     }

Tôi giả sử dữ liệu là nguyên thủy ints, có vẻ lành mạnh. Nhưng điều này hàm ý một hình phạt thời gian chạy cho java sử dụng, vì tính năng tự động đấm bốc, không cần thiết cho các khung bộ sưu tập nguyên thủy.

Các kết quả thời gian chạy (tất nhiên không có gc()cuộc gọi) trên WinXP, jdk1.6.0_10:

                      100000 đặt hoạt động 100000 chứa hoạt động 
bộ sưu tập java 1938 ms 203 ms
trove 234 ms 125 ms
pcj 516 ms 94 ms

Trong khi điều này có vẻ đã quyết liệt, đây không phải là lý do để sử dụng một khung như vậy.

Lý do là hiệu suất bộ nhớ. Kết quả cho một Bản đồ chứa 100000 intmục:

bộ sưu tập java dao động trong khoảng từ 6644536 đến 7168840 byte
trove 1853296 byte
pcj 1866112 byte

Bộ sưu tập Java cần bộ nhớ nhiều hơn ba lần so với các bộ sưu tập nguyên thủy. Tức là bạn có thể giữ dữ liệu nhiều gấp ba lần trong bộ nhớ mà không cần dùng đến IO đĩa làm giảm hiệu suất thời gian chạy theo cường độ. Và vấn đề này. Đọc highscalability để tìm hiểu lý do tại sao.

Theo kinh nghiệm của tôi, tiêu thụ bộ nhớ cao là vấn đề hiệu năng lớn nhất với Java, tất nhiên cũng dẫn đến hiệu năng thời gian chạy kém hơn. Khung bộ sưu tập nguyên thủy thực sự có thể giúp đỡ ở đây.

Vì vậy: Không, java.util không phải là câu trả lời. Và "thêm chức năng" vào các bộ sưu tập Java không phải là vấn đề khi hỏi về hiệu quả. Ngoài ra, các bộ sưu tập JDK hiện đại không "thực hiện ngay cả các bộ sưu tập Trove chuyên dụng".

Tuyên bố từ chối trách nhiệm: Điểm chuẩn ở đây còn lâu mới hoàn thành, cũng không hoàn hảo. Nó có nghĩa là để lái xe về nhà điểm, mà tôi đã trải nghiệm trong nhiều dự án. Các bộ sưu tập nguyên thủy đủ hữu ích để dung nạp API cá - nếu bạn làm việc với nhiều dữ liệu.


3
Trên thực tế, tôi nghĩ rằng câu trả lời của bạn là sai lệch. Lưu trữ ints vs Integers rất khác nhau, và rất có thể là lý do chính cho việc sử dụng bộ nhớ tăng lên. Tôi đồng ý một khung bộ sưu tập kiểu thô có thể hữu ích, nhưng nó không làm cho trove hoặc pcj "tốt hơn" java.util.
Jorn

22
Câu hỏi là về việc lưu trữ dữ liệu int hiệu quả. Không phải về lưu trữ số nguyên. Đối với nhiệm vụ này, trove / pcj hiệu quả hơn, như tôi đã cố gắng thể hiện. Sử dụng số nguyên áp đặt thời gian chạy và bộ nhớ không hiệu quả. Vì java.util không cho phép sử dụng nguyên thủy, nên nó không phải là lựa chọn tốt nhất cho nhiệm vụ này.
the.duckman

2
(đối với cộng đồng người Nga) ở đây sẽ có một điểm chuẩn khác: Total-holywar.blogspot.com/2011/07/ Kẻ
dma_k

Không chắc chắn nếu chúng ta không sử dụng int làm khóa, chỉ là Chuỗi bình thường. Điều gì sẽ là kết quả bàn làm việc cho họ?
Clark Bảo

@Clarkbao (xin lỗi vì đến trễ) Lưu trữ bất kỳ đối tượng nào làm khóa sẽ sử dụng đối tượng hashCode(). Nó giúp bạn có được một intchìa khóa.
Matthieu

47

Tôi biết đây là một bài viết cũ và có rất nhiều câu trả lời ở đây. Nhưng, các câu trả lời ở trên là hời hợt và quá đơn giản về mặt gợi ý một thư viện. Không có một thư viện nào thực hiện tốt các tiêu chuẩn khác nhau được trình bày ở đây. Kết luận duy nhất tôi rút ra là nếu bạn quan tâm đến hiệu suất và bộ nhớ và đặc biệt xử lý các kiểu nguyên thủy, thì đáng để xem xét các lựa chọn thay thế không jdk.

Dưới đây là một phân tích âm thanh hơn, về mặt cơ học chuẩn và các thư viện được bảo hiểm. Đây là một chủ đề trong danh sách dev mahout.

Các thư viện được bảo hiểm là

  • HPPC
  • Quân đội
  • FastUtil
  • Mahout (Colt)
  • Bộ sưu tập Java

Cập nhật tháng 6 năm 2015 : Thật không may, các điểm chuẩn ban đầu không còn nữa và bên cạnh đó là một chút lỗi thời. Đây là một điểm chuẩn khá gần đây (tháng 1 năm 2015) được thực hiện bởi người khác. Nó không toàn diện và cũng không có các công cụ thăm dò tương tác như liên kết ban đầu.


1
Cảm ơn bạn. Điều này rất hữu ích .. xem xét tầm quan trọng của câu hỏi, thật khó để tin rằng không có câu trả lời nào khác (ngoài câu trả lời) thực sự trả lời câu hỏi này.
Dexter

20

Như các nhà bình luận khác đã nhận thấy, định nghĩa "hiệu quả" tạo ra một mạng lưới rộng. Tuy nhiên chưa ai đề cập đến thư viện Javolution .

Một số điểm nổi bật:

  • Các lớp Javolution nhanh, rất nhanh (ví dụ: Chèn / xóa văn bản trong O [Log (n)] thay vì O [n] cho StringBuffer / StringBuilder tiêu chuẩn).
  • Tất cả các lớp Javolution đều tuân thủ theo thời gian thực cứng và có hành vi mang tính quyết định cao (trong phạm vi micro giây). Hơn nữa (không giống như thư viện chuẩn), Javolution là RTSJ an toàn (không có xung đột bộ nhớ hoặc rò rỉ bộ nhớ khi được sử dụng với tiện ích mở rộng Thời gian thực Java).
  • Các lớp tập hợp thời gian thực của Javolution (bản đồ, danh sách, bảng và tập hợp) có thể được sử dụng thay cho hầu hết các lớp bộ sưu tập tiêu chuẩn và cung cấp chức năng bổ sung.
  • Các bộ sưu tập Javolution cung cấp các đảm bảo đồng thời để thực hiện các thuật toán song song dễ dàng hơn.

Phân phối Javolution bao gồm một bộ điểm chuẩn để bạn có thể thấy cách chúng xếp chồng lên các thư viện khác / các bộ sưu tập tích hợp.


16

Một số libs bộ sưu tập để xem xét:

Trước tiên tôi sẽ tiếp cận với thư viện bộ sưu tập JDK. Nó bao gồm hầu hết những điều phổ biến bạn cần làm và rõ ràng là đã có sẵn cho bạn.

Bộ sưu tập của Google có lẽ là thư viện chất lượng cao tốt nhất ngoài JDK. Nó được sử dụng nhiều và được hỗ trợ tốt.

Bộ sưu tập Apache Commons cũ hơn và chịu một chút vấn đề "quá nhiều đầu bếp" nhưng cũng có rất nhiều công cụ hữu ích.

Trove có các bộ sưu tập rất chuyên biệt cho các trường hợp như khóa / giá trị nguyên thủy. Ngày nay, chúng ta thấy rằng trên các JDK hiện đại và với các bộ sưu tập Java 5+ và các trường hợp sử dụng đồng thời, các bộ sưu tập JDK thực hiện ngay cả các bộ sưu tập Trove chuyên dụng.

Nếu bạn có các trường hợp sử dụng đồng thời thực sự cao, bạn chắc chắn nên kiểm tra những thứ như NonBlockingHashMap trong lib quy mô cao, đây là một triển khai không có khóa và có thể dậm chân trên ConcảnHashMap nếu bạn có trường hợp sử dụng phù hợp cho nó.


7
"Ngày nay, chúng tôi thấy rằng trên các JDK hiện đại và với các bộ sưu tập Java 5+ và các trường hợp sử dụng đồng thời, các bộ sưu tập JDK thực hiện ngay cả các bộ sưu tập Trove chuyên dụng." Gây hiểu lầm - Tôi chưa bao giờ thấy một điểm chuẩn vi mô trong đó lưu trữ / truy xuất các kiểu nguyên thủy trong lớp bộ sưu tập nguyên thủy chuyên biệt như Trove không vượt trội so với các lớp bộ sưu tập JDK về cả thời gian sử dụng bộ nhớ và thời gian CPU. Nếu bạn đang sử dụng các đối tượng mặc dù (và không phải kiểu nguyên thủy), thì tôi sẽ đồng ý với Alex, việc băn khoăn về bộ sưu tập không phải là vấn đề lớn.
Riyad Kalla

2
Tuyên bố này dựa trên việc sử dụng thế giới thực nặng nề (mà tôi sẽ tiếp quản điểm chuẩn vi mô bất kỳ ngày nào) của bộ sưu tập khác nhau ngụ ý rằng trước đây chúng tôi cần một bộ sưu tập Trove nhưng giờ đã có thể rút nó ra. Các bản cập nhật JDK 6 muộn (khoảng cuối năm 2009) thực sự đã cung cấp mã tùy chỉnh cho các khóa bản đồ phổ biến như Integer đã cải thiện đáng kể một số cách sử dụng phổ biến nhất.
Alex Miller

1
Alex, tôi không nghi ngờ gì trong các trường hợp sử dụng cụ thể của bạn khi lấy ra các bộ sưu tập nguyên thủy và đi với các bộ sưu tập JDK là đủ nhanh, nhưng vẫy tay qua phong cảnh là các bộ sưu tập và nói "Tất cả các bạn đều vượt qua, nó đủ nhanh! " không chính xác. Nếu tôi đang làm việc trên một công cụ trò chơi 2D, thì chi phí đấm bốc / mở hộp các loại nguyên thủy của tôi liên tục đắt đỏ. Nếu tôi đang làm việc với API REST thì không, có lẽ nó không tạo ra sự khác biệt có thể đo lường được đối với các op đắt tiền hơn nhiều như HTTP I / O. Tôi chỉ cảm thấy bắt buộc phải định lượng bài viết của bạn là tất cả.
Riyad Kalla

4
Tôi không nghĩ bất cứ ai đọc nó nên lắng nghe chúng tôi. Họ nên kiểm tra trường hợp sử dụng của riêng mình và xem những gì có hiệu suất tốt nhất. Nhận xét của tôi dựa trên các bài kiểm tra hiệu suất khá tích cực của nhóm tôi với nhiều thư viện khác nhau. YMMV.
Alex Miller

2
Tôi đồng ý với @Riyad. Tôi đang viết một bộ automata hữu hạn hiệu suất cao và đã triển khai nó với cả Trove và Java Coll Collection Framework (bản cập nhật mới nhất của jdk 6). Trove vượt trội hơn thời gian lớn. Theo thứ tự tốt hơn hàng chục lần cả về tốc độ tính toán và mức tiêu thụ bộ nhớ.
Nico Huysamen

6

java.util

Xin lỗi vì câu trả lời rõ ràng, nhưng đối với hầu hết các mục đích sử dụng, Bộ sưu tập Java mặc định là quá đủ.


4
Đối với sử dụng cơ bản, có. Nhưng tôi nghĩ rằng khung công tác bỏ lỡ một số tính năng cơ bản và nâng cao (như bộ sưu tập, bộ lọc, đa khung, v.v.) và đó là nơi (ví dụ) Bộ sưu tập Google xuất hiện
Jorn

1
Tôi nghĩ rằng câu trả lời này bỏ lỡ điểm. JCF có lẽ là tuyệt vời vào năm 2002 khi mọi người không sử dụng Java nhiều. Thật không may, nó không có tuổi, đặc biệt là khi so sánh với các bộ sưu tập hỗ trợ từ các ngôn ngữ JVM khác.
Ted Pennings

3
-1 Câu hỏi là "hiệu quả nhất để lưu trữ int" và bất kỳ ví dụ nào được đề cập đều tốt hơn java.util
kommradHomer



3

java.util.concurrentNên đề cập đến concienHashMap cũng như gói, nếu bạn có kế hoạch sử dụng HashMap trong nhiều luồng. dấu chân bộ nhớ nhỏ được đảm bảo, vì đây là một phần của java tiêu chuẩn.


3

Phụ thuộc vào cách chúng tôi định nghĩa "hiệu quả".

Mỗi cấu trúc dữ liệu có hành vi Big-Oh riêng để đọc, viết, lặp, dấu chân bộ nhớ, v.v ... Một danh sách được liên kết trong một thư viện có thể giống như bất kỳ thư viện nào khác. Và bản đồ băm sẽ nhanh hơn để đọc O (1) so với danh sách được liên kết O (n).

Nhưng khi tôi đọc câu trả lời cho câu hỏi "Thư viện Java miễn phí hữu ích nhất?" Tôi nhận thấy rằng trove hầu như không được đề cập.

Điều này không có vẻ như "hiệu quả nhất". Nghe có vẻ như "phổ biến nhất" đối với tôi.

Chỉ cần một số phản hồi - tôi chưa bao giờ nghe về nó và tôi không biết ai đã sử dụng nó. Các bộ sưu tập được tích hợp trong JDK, Google hoặc Apache Commons nổi tiếng với tôi.


3

Trove cung cấp một vài lợi thế.

  • dung lượng bộ nhớ nhỏ hơn, nó không sử dụng các đối tượng Map.Entry
  • bạn có thể sử dụng chiến lược băm thay cho các khóa cho bản đồ, điều này giúp tiết kiệm bộ nhớ và có nghĩa là bạn không cần xác định khóa mới mỗi khi bạn muốn lưu trữ một đối tượng trên một bộ thuộc tính mới của nó
  • nó có các kiểu sưu tập nguyên thủy
  • nghĩ rằng nó có một số hình thức lặp nội bộ

Điều đó nói rằng, rất nhiều đã được thực hiện để cải thiện các bộ sưu tập jdk kể từ khi trove được viết.

Đó là các chiến lược băm làm cho nó hấp dẫn đối với tôi mặc dù ... Google để tìm hiểu và đọc tổng quan của họ.


2

Nếu bạn muốn lưu trữ hàng triệu bản ghi trong bảng băm, rất có thể bạn sẽ gặp vấn đề về bộ nhớ. Điều này đã xảy ra với tôi khi tôi thử tạo một bản đồ với 2,3 triệu đối tượng String chẳng hạn. Tôi đã đi với BerkeleyDB , rất trưởng thành và hoạt động tốt. Họ có API Java bao bọc API Bộ sưu tập, do đó bạn có thể dễ dàng tạo các bản đồ lớn tùy ý với rất ít bộ nhớ. Truy cập sẽ chậm hơn mặc dù (vì nó được lưu trữ trên đĩa).

Câu hỏi tiếp theo : có một thư viện phong nha (và hiệu quả), được duy trì tốt cho các bộ sưu tập bất biến không? Clojure có sự hỗ trợ tuyệt vời cho việc này và thật tuyệt khi có một cái gì đó tương tự cho Java.


1
Bộ sưu tập của Google thêm Bộ sưu tập bất biến.
the.duckman
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.