가장 효율적인 Java Collections 라이브러리는 무엇입니까? [닫은]


135

가장 효율적인 Java Collections 라이브러리는 무엇입니까?

몇 년 전, 나는 자바를 많이했고, 그때 인상을 가지고 발견 물이 최고 (가장 효율적인) 자바 컬렉션 구현입니다. 그러나 " 가장 유용한 무료 Java 라이브러리? "라는 질문에 대한 답변을 읽었을 때 나는 그 말이 거의 언급되지 않았다는 것을 알았습니다 . 그렇다면 현재 가장 좋은 Java Collections 라이브러리는 무엇입니까?

업데이트 : 명확히하기 위해 해시 테이블 등에 수백만 개의 항목을 저장해야 할 때 사용하는 라이브러리를 알고 싶습니다 (작은 런타임 및 메모리 풋 프린트 필요).


이 표의 키와 값은 무엇입니까? 그것들이 프리미티브가 아니라면, 일반적인 HashMap 등에 어떤 문제가 있습니까?
Jon Skeet

매우 큰 맵의 경우 프로빙 구현을 원하거나 데이터베이스 테이블처럼 인라인 될 수도 있습니다.
Tom Hawtin-tackline

1
흥미롭게도 나는 여기서 Maht에 포함 된 Colt에 대한 언급이 없습니다.
smartnut007

4
GS 컬렉션 (github.com/goldmansachs/gs-collections)과 같은 훌륭한 컬렉션 라이브러리를 언급 할 가치가 있습니다. 그것은 훌륭한 문서와 철저한 변경 가능하고 불변의
컬렉션을 가지고 있습니다

답변:


73

검사에서 Trove는 기본 유형의 컬렉션 라이브러리 일뿐입니다 .JDK의 일반 컬렉션보다 많은 기능을 추가하려는 것은 아닙니다.

개인적으로 (그리고 나는 편견입니다) 구아바 (구 구글 자바 컬렉션 프로젝트 포함 )를 좋아 합니다. 최소한 합리적으로 효율적인 방식으로 다양한 작업 (컬렉션 포함)을 훨씬 쉽게 만듭니다. 콜렉션 작업이 내 코드에서 병목 현상을 거의 일으키지 않는다는 것을 감안할 때 (내 경험상) 이것은 콜렉션 API보다 "더 나은"데, 이는 더 효율적일 수 있지만 코드를 읽을 수있는 것으로 만들지는 않습니다.

Trove와 Guava의 중복이 거의없는 경우 컬렉션 라이브러리에서 실제로 찾고있는 내용을 명확하게 설명 할 수 있습니다.


3
@Andreas : 동의한다고 말할 수 없습니다. 그것이 "하나 또는 다른"시나리오라는 것이 아닙니다. 나는 Lists 클래스와 같은 도우미와 함께 일반 컬렉션을 사용하고 필요할 때 Iterables 등을 사용합니다. 도움이 될 때만 복잡성을 사용하십시오.
Jon Skeet

10
GC를 광범위하게 사용한 후 몇 달 동안 자신의 의견을 읽은 후-나는 과거 의견에 동의하지 않으며 귀하의 의견에 전적으로 동의합니다. 헬퍼 메소드 / 클래스를 광범위하게 사용하면 많은 코드를 더 읽기 쉽고 안전하게 만듭니다.
Andreas Petersson

1
@Andreas : 돌아와 주셔서 감사합니다-GJC가 도와 주신 것을 기쁘게 생각합니다 :)
Jon Skeet

2
Jon, Google Java Collections는 이제 구아바 입니다. 나중에 참조 할 수 있도록 게시물을 업데이트하고 싶을 수도 있습니다 :)
Artur Czajka

1
컬렉션이 큰 병목 현상이 발생한 데이터 집약적 인 프로젝트를 많이 수행했습니다. 자바 컬렉션은 특히 프리미티브를 저장하는 경우 메모리와 속도 모두 매우 비효율적입니다.
Jay Askren

104

문제는 (현재) 많은 데이터를 저장하는 것에 관한 것입니다.이 데이터는와 같은 기본 유형을 사용하여 나타낼 수 있습니다 int. 여기에 대한 답변 중 일부는 내 의견으로는 매우 오도됩니다. 왜 그런지 보자.

런타임과 메모리 소비를 모두 측정하기 위해 Trove 에서 벤치 마크를 수정했습니다 . 또한 이 벤치 마크 에 PCJ 를 추가 했습니다.이 벤치 마크는 기본 유형에 대한 또 다른 콜렉션 라이브러리입니다 (저는 광범위하게 사용합니다). '공식적인'트 로브 벤치 마크는 IntIntMaps와 Java Collection의 비교를하지 않습니다 Map<Integer, Integer>. 아마도 저장 Integers과 저장 ints은 기술적 인 관점에서 같지 않을 것입니다. 그러나 사용자는이 기술적 인 세부 사항에 신경 쓰지 않을 수 있으며 ints효율적으로 표현할 수있는 데이터를 저장하려고합니다 .

먼저 코드의 관련 부분 :

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

나는 데이터가 원시적이라고 가정하고 ints제정신처럼 보인다. 그러나 이것은 원시 복싱 프레임 워크에 필요하지 않은 자동 복싱으로 인해 java util에 대한 런타임 페널티를 의미합니다.

gc()WinXP에서 jdk1.6.0_10 의 런타임 결과 ( 물론 호출 하지 않음 ) :

                      100000 넣기 작업 100000에는 작업이 포함됩니다 
자바 컬렉션 1938 ms 203 ms
트로이 234ms 125ms
pcj 516ms 94ms

이것은 이미 과감하게 보일지 모르지만 이것이 그러한 프레임 워크를 사용하는 이유는 아닙니다.

그 이유는 메모리 성능입니다. 100000 int개의 항목이 포함 된 맵의 결과 :

Java 콜렉션이 6644536과 7168840 바이트 사이에서 진동합니다.
트로이 1853296 바이트
pcj 1866112 바이트

Java Collections 는 프리미티브 콜렉션 프레임 워크에 비해 3 배 이상의 메모리 필요합니다 . 즉, 런타임 성능을 크게 저하시키는 디스크 IO에 의존하지 않고 메모리에 3 배 많은 데이터를 유지할 수 있습니다. 그리고 이것은 중요합니다. 그 이유를 알아 보려면 높은 확장 성 을 읽으십시오 .

내 경험에 따르면 높은 메모리 소비는 Java의 가장 큰 성능 문제이며 물론 런타임 성능도 저하됩니다. 프리미티브 콜렉션 프레임 워크가 실제로 도움이 될 수 있습니다.

따라서 : 아니오, java.util은 답이 아닙니다. Java 컬렉션에 "기능 추가"는 효율성을 요구할 때 중요하지 않습니다. 또한 최신 JDK 컬렉션은 "특수한 Trove 컬렉션보다 성능이 우수 하지 않습니다 ".

면책 조항 : 여기서 벤치 마크는 완전하지도 않고 완벽하지도 않습니다. 그것은 많은 프로젝트에서 경험했던 요점을 집으로 몰아 넣는 것입니다. 기본 컬렉션은 많은 양의 데이터로 작업하는 경우 비린내 API를 견딜 수있을 정도로 유용 합니다.


3
사실, 나는 당신의 대답이 오도라고 생각합니다. 정수와 정수를 저장하는 것은 매우 다르며, 메모리 사용량이 증가한 주된 이유 일 것입니다. 나는 raw type collection 프레임 워크가 유용 할 수 있지만, java.util보다 trove 나 pcj를 더 낫게 만들지는 않는다는 데 동의한다.
Jorn

22
문제는 int 데이터를 효율적으로 저장하는 것입니다. 정수 저장에 관한 것이 아닙니다. 이 작업에서는 trove / pcj가 더 효율적입니다. 정수를 사용하면 런타임 및 메모리 비효율이 발생합니다. java.util은 기본 요소의 사용을 허용하지 않으므로이 태스크에 가장 적합한 선택은 아닙니다.
the.duckman

2
(러시아 공동체를 위해) 여기 또 다른 벤치 마크가 있습니다 : total-holywar.blogspot.com/2011/07/…
dma_k

int를 키로 사용하지 않는지 확실하지 않으면 일반 문자열입니다. 그들을위한 작업대 결과는 무엇입니까?
Clark Bao

@ClarkBao (늦어서 죄송합니다) 객체를 키로 저장하면 객체가 사용됩니다 hashCode(). 그것은 int열쇠로서 당신을 얻는다 .
Matthieu

47

나는 이것이 오래된 게시물이라는 것을 알고 있으며 여기에 많은 대답이 있습니다. 그러나 위의 답변은 도서관 제안 측면에서 피상적이고 단순합니다. 여기에 제시된 다양한 벤치 마크에서 잘 작동하는 라이브러리는 없습니다. 내가 얻는 유일한 결론은 성능과 메모리에 관심이 있고 특히 원시 유형을 다루는 경우 비 jdk 대안을 살펴볼 가치가 있다는 것입니다.

다음은 벤치 마크 역학 및 해당 라이브러리와 관련하여보다 건전한 분석입니다. 이것은 mahout dev 목록의 스레드입니다.

다루는 도서관은

  • HPPC
  • 트 로브
  • FastUtil
  • 마 흐트 (콜트)
  • 자바 컬렉션

2015 년 6 월 업데이트 : 불행히도 원래 벤치 마크는 더 이상 사용할 수 없으며 약간 오래된 것입니다. 다음 은 다른 사람이 수행 한 상당히 최근 (2015 년 1 월) 벤치 마크입니다. 그것은 포괄적이 아니며 대화 형 탐색 도구를 원본 링크만큼 가지고 있지 않습니다.


1
감사합니다. 이것은 매우 도움이되었습니다 .. 질문의 중요성을 고려하면 (duckman 이외의) 다른 답변들 중 어느 것도 실제로이 질문에 대답하지 않는다고 믿기가 어렵습니다.
Dexter

20

다른 논평가들이 알듯이, "효율적인"의 정의는 넓은 그물을 던진다. 그러나 아직 아무도 Javolution 라이브러리를 언급하지 않았습니다 .

일부 하이라이트 :

  • Javolution 클래스는 빠르고 매우 빠릅니다 (예 : 표준 StringBuffer / StringBuilder의 경우 O [n] 대신 O [Log (n)]의 텍스트 삽입 / 삭제).
  • 모든 Javolution 클래스는 실시간에 적합하지 않으며 결정적인 동작 (마이크로 초 범위)을 갖습니다. 또한 표준 라이브러리와 달리 Javolution은 RTSJ 안전합니다 (Java Real-Time 확장과 함께 사용할 경우 메모리 충돌 또는 메모리 누수 없음).
  • Javolution의 실시간 컬렉션 클래스 (맵, 목록, 테이블 및 세트)는 대부분의 표준 컬렉션 클래스 대신 사용할 수 있으며 추가 기능을 제공합니다.
  • Javolution 컬렉션은 동시성 보장을 제공하여 병렬 알고리즘을보다 쉽게 ​​구현할 수 있습니다.

Javolution 배포판에는 벤치 마크 모음이 포함되어있어 다른 라이브러리 / 내장 모음과 비교하여 어떻게 누적되는지 확인할 수 있습니다.


16

고려해야 할 일부 콜렉션 라이브러리 :

우선 JDK 콜렉션 라이브러리에 도달했습니다. 그것은 당신이해야 할 가장 일반적인 일을 다루고 있으며 분명히 당신에게 이미 사용 가능합니다.

Google 컬렉션은 아마도 JDK 외부의 최고의 고품질 라이브러리 일 것입니다. 많이 사용되고 잘 지원됩니다.

Apache Commons Collections는 오래되었으며 "너무 많은 요리사"문제로 인해 어려움을 겪지 만 유용한 정보가 많이 있습니다.

Trove는 프리미티브 키 / 값과 같은 경우를 위해 매우 전문화 된 컬렉션을 보유하고 있습니다. 요즘 우리는 현대 JDK와 Java 5+ 컬렉션 및 동시 사용 사례에서 JDK 컬렉션이 특수한 Trove 컬렉션보다 성능이 뛰어납니다.

동시성 사용 사례가 실제로 높은 경우, 고급 라이브러리에서 NonBlockingHashMap과 같은 항목을 확인해야합니다. 이는 잠금이없는 구현이며 올바른 사용 사례가 있으면 ConcurrentHashMap에서 스톰 핑 할 수 있습니다.


7
"현재 우리는 최신 JDK와 Java 5+ 컬렉션 및 동시 사용 사례에서 JDK 컬렉션이 특수한 Trove 컬렉션보다 성능이 뛰어납니다." 오해의 소지-Trove와 같은 특수한 프리미티브 컬렉션 클래스에서 프리미티브 유형을 저장 / 검색하는 것이 메모리 사용 및 CPU 시간에서 JDK 컬렉션 클래스를 능가하지 않는 마이크로 벤치 마크를 본 적이 없습니다. 비록 원시적 유형이 아닌 객체를 사용하고 있다면 Alex에 동의 할 것입니다. 컬렉션 impl에 대한 프렛 팅은 그다지 중요하지 않습니다.
리야드 칼라

2
이 진술은 우리가 이전에 Trove 수집을 필요로했지만 지금 그것을 뽑아 낼 수 있었던 다양한 수집 impls의 많은 실제 사용 (언제나 마이크로 벤치 마크를 취할 것입니다)을 기반으로했습니다. 늦은 JDK 6 업데이트 (2009 년 말)는 실제로 가장 일반적인 용도 중 일부를 크게 개선 한 Integer와 같은 공통 맵 키에 대한 사용자 지정 코드를 실제로 제공했습니다.
Alex Miller

1
Alex, 나는 특정 유스 케이스에서 원시 콜렉션을 꺼내고 JDK 콜렉션을 사용하는 것이 충분히 빠르다는 것을 의심하지 않습니다. 그러나 콜렉션 인 풍경을 가로 질러 손을 흔들며 "그렇습니다. " 정확하지 않습니다. 2D 게임 엔진을 사용하는 경우 필연적으로 기본 유형의 박싱 / 언 박싱 오버 헤드는 상당히 비쌉니다. REST API를 사용하고 있다면 아니오, 아마도 HTTP I / O와 같은 훨씬 더 비싼 ops와 관련하여 측정 가능한 차이를 만들지 않을 것입니다. 난 그냥 당신의 게시물을 정량화해야한다고 느꼈습니다.
리야드 칼라

4
나는 이것을 읽는 사람이 우리 중 하나의 말을 들어야한다고 생각하지 않습니다. 그들은 자신의 유스 케이스를 테스트하고 최고의 성능을 가진 것을 확인해야합니다. 내 의견은 다양한 라이브러리를 갖춘 팀의 상당히 공격적인 성능 테스트를 기반으로합니다. YMMV.
Alex Miller

2
@Riyad에 동의합니다. 고성능 유한 오토마타 제품군을 작성 중이며 Trove 및 Java Collections Framework (jdk 6 최신 업데이트)로 구현했습니다. Trove는 큰 시간을 능가합니다. 계산 속도와 메모리 소비 모두에서 수십 배 더 우수합니다.
니코 Huysamen

6

java.util

분명한 대답은 유감이지만 대부분의 경우 기본 Java 콜렉션 으로 충분합니다.


4
기본적인 용도로는 그렇습니다. 하지만 프레임 워크에는 불변 컬렉션, 필터, 멀티 맵 등과 같은 기본 및 고급 기능이 누락되어 Google 컬렉션이 제공되는 곳이 있습니다.
Jorn

1
이 답변이 요점을 놓친 것 같습니다. JCF는 사람들이 Java를 많이 사용하지 않았던 2002 년에 아마도 대단했습니다. 불행히도 특히 다른 JVM 언어의 컬렉션 지원과 비교할 때 잘 노화되지 않았습니다.
Ted Pennings

3
-1이 질문은 "int 저장에 가장 효율적"이며 언급 된 예는 java.util보다 낫습니다
kommradHomer



3

java.util.concurrent여러 스레드에서 HashMap을 사용하려는 경우 패키지 뿐만 아니라 ConcurrentHashMap 도 언급해야합니다. 표준 Java의 일부이므로 작은 메모리 풋 프린트가 발생합니다.


3

"효율적인"정의 방법에 따라 다릅니다.

모든 데이터 구조에는 읽기, 쓰기, 반복, 메모리 풋 프린트 등을위한 고유 한 Big-Oh 동작이 있습니다. 한 라이브러리의 링크 된 목록은 다른 라이브러리와 동일 할 것입니다. 그리고 해시 맵은 연결된 목록 O (n)보다 O (1)을 읽는 것이 더 빠릅니다.

그러나 "가장 유용한 무료 Java 라이브러리?"라는 질문에 대한 답변을 읽을 때 나는 trove가 거의 언급되지 않았다는 것을 알아 차렸다.

이것은 "가장 효율적"인 것처럼 들리지 않습니다. 나에게 "가장 인기있는"것 같습니다.

그냥 피드백-들어 본 적이 없으며, 그것을 사용한 사람을 모른다. JDK, Google 또는 Apache Commons에 내장 된 컬렉션은 저에게 잘 알려져 있습니다.


3

Trove는 몇 가지 장점을 제공합니다.

  • 더 작은 메모리 공간, Map.Entry 객체를 사용하지 않습니다
  • 맵에 키 대신 해시 전략을 사용할 수 있습니다. 이렇게하면 메모리가 절약되므로 새로운 속성 세트에서 객체를 캐시 할 때마다 새 키를 정의 할 필요가 없습니다.
  • 기본 컬렉션 유형이 있습니다
  • 내부 반복자의 형태가 있다고 생각합니다.

즉, trove가 작성된 이후 jdk 콜렉션을 개선하기 위해 많은 작업이 수행되었습니다.

Google에 감사를 표하는 해싱 전략입니다.


2

해시 테이블에 수백만 개의 레코드를 저장하려는 경우 메모리 문제가 발생할 가능성이 있습니다. 예를 들어 230 만 개의 String 객체로 맵을 만들려고했을 때 이런 일이 일어났습니다. 나는 매우 성숙하고 잘 수행하는 BerkeleyDB 와 함께 갔다 . Collections API를 래핑하는 Java API가 있으므로 메모리 사용량이 거의없는 임의의 큰 맵을 쉽게 만들 수 있습니다. 그러나 디스크에 저장되므로 액세스 속도가 느려집니다.

후속 질문 : 불변의 컬렉션을위한 적절한 (그리고 효율적이며) 잘 관리 된 라이브러리가 있습니까? Clojure는 이것을 훌륭하게 지원하며 Java와 비슷한 것을 갖는 것이 좋습니다.


1
Google 컬렉션은 불변 컬렉션을 추가합니다.
the.duckman 2016 년
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.