JavaRush /Java Blog /Random-KO /Java 컬렉션에 관한 상위 10가지 질문
FedoraLinux
레벨 21
Москва

Java 컬렉션에 관한 상위 10가지 질문

Random-KO 그룹에 게시되었습니다
이 기사는 " Java 컬렉션에 관한 상위 10가지 질문 " 기사를 번역한 것입니다 . 다음은 Stackowerflow에서 질문하고 토론한 Java 컬렉션에 관한 가장 인기 있는 질문입니다. 이러한 질문을 보기 전에 클래스 계층 다이어그램을 살펴보는 것이 좋습니다. 1. ArrayList 대신 LinkedList를 언제 사용해야 합니까? ArrayList 는 실제로 배열이므로 해당 요소는 인덱스를 통해 직접 액세스할 수 있습니다. 배열이 오버플로되면 더 많은 공간이 있는 새 배열이 필요합니다. 모든 요소를 ​​배치하고 이동하는 데는 O(n) 시간이 걸립니다. 또한 배열의 기존 요소를 이동하려면 요소를 추가하고 제거해야 합니다. 이것이 아마도 ArrayList를 사용할 때 가장 큰 불편함일 것입니다. LinkedList는 요소 링크의 이중 목록입니다. 따라서 중앙에 있는 요소에 접근하려면 시트의 맨 처음부터 끝까지 검색해야 합니다. 반면에 LinkedList에서 요소를 추가하고 제거하는 작업은 목록 자체만 변경하므로 더 빠릅니다. 최악의 시간은 다음과 같습니다.
방법 배열 목록 링크드리스트
get(인덱스) 오(1) 에)
추가(E) 에) 오(1)
추가(E, 인덱스) 에) 에)
제거(색인) 에) 에)
반복자.제거() 에) 오(1)
반복자.추가(E) 에) 오(1)
실행 시간에도 불구하고 큰 목록의 경우 메모리 사용량을 개별적으로 고려해야 합니다. LinkedList에서는 각 노드에 이전 노드와 다음 노드를 연결하기 위한 추가 포인터가 두 개 이상 있어야 하지만 ArrayList에서는 요소 배열만 필요합니다. ArrayList, LinkedList 및 Vector 목록 에 대한 추가 비교 . 2. 컬렉션 반복 중에 요소를 제거하는 효율적인 방법 반복 중에 컬렉션을 수정(요소 제거)하는 유일한 올바른 방법은 Iterator.remove() 를 사용하는 것입니다 . 예: 가장 일반적인 오류는 다음과 같습니다. 위 코드를 실행하는 동안 ConcurrentModificationException이 발생합니다 . 이는 전체 목록을 이동하도록 반복자가 생성되었지만 동시에 Iterator.remove()를 호출하여 시트가 변경되기 때문에 발생합니다. 이 예외에 대한 문서에 기록된 대로, Iterator itr = list.iterator(); while(itr.hasNext()) { // do something itr.remove(); } for(Integer i: list) { list.remove(i); }
"일반적으로 한 스레드가 컬렉션을 수정하는 동안 다른 스레드가 컬렉션을 반복하는 것은 허용되지 않습니다."
일반적으로 한 스레드가 컬렉션을 탐색하는 동안 다른 스레드가 컬렉션을 수정하는 것은 허용되지 않습니다. 3. List를 int[] 배열로 변환하는 방법은 무엇입니까? 가장 쉬운 방법은 Apache Commons Lang 라이브러리 에 있는 ArrayUtils를 사용하는 것입니다 . JDK에는 이 표현식에 대한 지름길이 없습니다. 이 표현식은 List를 Integer[]( 기본 유형이 아님 ) 로 변환하기 때문에 List.toArray()를 사용할 수 없다는 점을 기억하십시오 . 올바른 방법은 다음 옵션입니다. 4. int[] 배열을 목록으로 변환하는 방법은 무엇입니까? 가장 쉬운 방법은 위와 같이 Apache Commons Lang 라이브러리 에서 ArrayUtils를 사용하는 것입니다. 또한 JDK에는 이 표현식에 대한 지름길이 없습니다. 5. 컬렉션을 필터링하는 가장 좋은 방법은 무엇입니까? Guava 또는 Apache Commons Lang 과 같은 타사 패키지를 사용하여 기능을 향상할 수 있습니다. 이 두 패키지에는 모두 filter() 메서드( Guava의 Collections2 클래스 와 Apache의 CollectionUtils )가 있습니다. filter() 메소드는 주어진 Predicate와 일치하는 요소를 반환합니다. JDK에서는 모든 것이 더 복잡합니다. 좋은 소식은 Java 8에 조건자가 추가된다는 것입니다 . 하지만 지금은 전체 컬렉션을 반복하려면 Iterator를 사용해야 합니다. 물론 새로운 Predicate 인터페이스에 익숙해지면 Guava 및 Apache가 따르는 경로를 모방할 수 있습니다. 이제 다음 코드를 사용하여 컬렉션을 필터링할 수 있습니다. 6. List를 Set으로 쉽게 변환하는 방법은 무엇입니까? 평등을 정의하는 방법에 따라 이를 수행하는 방법에는 두 가지가 있습니다. 첫 번째 코드 조각은 목록을 HashSet에 넣습니다. 이 경우 중복은 주로 hashCode()에 의해 결정됩니다. 일반적으로 이것은 작동합니다. 그러나 비교 경로를 고려해야 하는 경우에는 코드의 두 번째 부분을 사용하여 자신만의 비교기를 정의하는 것이 좋습니다. 7. ArrayList에서 중복 요소를 제거하려면 어떻게 해야 합니까? 이 질문은 위의 질문과 어느 정도 관련이 있습니다. ArrayList의 요소 순서가 중요하지 않은 경우 시트를 Set에 배치하여 중복 항목을 제거한 다음 다시 List로 되돌리는 것이 현명한 방법입니다. 아래는 예시입니다. 요소의 순서가 중요하다면 표준 JDK에 있는 LinkedHashSet 에 목록을 배치하여 순서를 보장할 수 있습니다. 8. 정렬된 컬렉션 int[] array = ArrayUtils.toPrimitive(list.toArray(new Integer[0])); int[] array = new int[list.size()]; for(int i=0; i < list.size(); i++) { array[i] = list.get(i); } List list = Arrays.asList(ArrayUtils.toObject(array)); int[] array = {1,2,3,4,5}; List list = new ArrayList (); for(int i: array) { list.add(i); } Iterator itr = list.iterator(); while(itr.hasNext()) { int i = itr.next(); if (i > 5) { // filter all ints bigger than 5 itr.remove(); } } public interface Predicate { boolean test(T o); } public static void filter(Collection collection, Predicate predicate) { if ((collection != null) && (predicate != null)) { Iterator itr = collection.iterator(); while(itr.hasNext()) { T obj = itr.next(); if (!predicate.test(obj)) { itr.remove(); } } } } filter(list, new Predicate () { public boolean test(Integer i) { return i <= 5; } }); Set set = new HashSet (list); Set set = new TreeSet (aComparator); set.addAll(list); ArrayList** list = ... // initial a list with duplicate elements Set set = new HashSet (list); list.clear(); list.addAll(set); Java에서 정렬된 컬렉션을 지원하는 방법에는 여러 가지가 있습니다. 이들 모두는 자연 순서로 또는 지정된 비교기에 의해 컬렉션을 제공합니다. 자연 순서의 경우 요소에 Comparable 인터페이스도 구현해야 합니다.
  1. Collections.sort()는 목록을 정렬할 수 있습니다. Java 문서에 명시된 대로 이 정렬은 안정적이며 n log(n) 성능을 보장합니다.
  2. PriorityQueue는 질서정연한 대기열을 제공합니다. PriorityQueue와 Collections.sort()의 차이점은 PriorityQueue가 항상 대기열의 순서를 유지하지만 대기열의 첫 번째 요소만 가져올 수 있다는 것입니다. PriorityQueue.get(4)과 같은 요소에는 무작위로 액세스할 수 없습니다.
  3. 컬렉션에 중복 항목이 없으면 TreeSet 을 선택할 수 있습니다 . PriorityQueue와 마찬가지로 TreeSet은 항상 순서가 지정된 세트를 유지합니다. TreeSet에서 가장 작거나 가장 큰 요소를 가져올 수 있지만 여전히 해당 요소에 무작위로 액세스할 수는 없습니다.
간단히 말해서 Collections.sort()는 일회성 정렬 목록을 제공합니다. PriorityQueue 및 TreeSet은 요소에 대한 색인화된 액세스가 부족하여 항상 순서가 지정된 컬렉션을 유지합니다. 9. Collections.emptyList() 또는 새 인스턴스 emptyMap() 및emptySet()에도 동일한 질문이 적용됩니다. 두 메서드 모두 빈 목록을 반환하지만 Collections.emptyList()는 변경할 수 없는 목록입니다. 이는 "빈" 목록에 새 요소를 추가 할 수 없음을 의미합니다. 백그라운드에서 Collections.emptyList() 메서드를 호출할 때마다 실제로는 빈 목록의 새 인스턴스가 생성되지 않습니다. 대신, 이미 존재하는 빈 인스턴스를 재사용합니다. 디자인 패턴으로 싱글턴에 익숙하다면 , 그 의미를 이해해야 합니다. 자주 호출하면 성능이 향상 됩니다 . 10 컬렉션 복사, Collections.copy() 소스 목록을 대상 목록으로 복사하는 방법에는 두 가지가 있습니다. 한 가지 방법은 ArrayList 생성자를 사용하는 것입니다. 또 다른 방법은 Collections.copy() 메서드를 사용하는 것입니다 . 첫 번째 줄에 주의하세요. 컬렉션에 대한 Java 문서에 다음과 같이 나와 있으므로 원본 목록의 길이와 최소한 동일한 길이의 목록을 할당합니다. ArrayList dstList = new ArrayList (srcList);
대상 목록은 최소한 소스 목록보다 길어야 합니다.
즉, 최종 목록은 원본 목록보다 짧아서는 안 됩니다. 두 방법 모두 얕은 복사입니다. 그렇다면 이 두 가지 방법의 차이점은 무엇입니까? 첫째, dstList에 srcList의 모든 요소를 ​​포함할 공간이 충분하지 않은 경우에도 Collections.copy()는 dstList 컬렉션의 용량을 재할당하지 않습니다. 대신 IndexOutOfBoundsException 이 발생합니다 . 이것에 어떤 이점이 있는지 물어볼 수도 있습니다. 그 이유는 메소드가 시간에 따라 선형적으로 실행되도록 보장하기 때문입니다. 이는 ArrayList 생성자에서 메모리를 다시 할당하는 대신 배열을 재사용하려는 경우에도 적합합니다. 결론 대신 기사를 읽은 후에도 여전히 궁금한 점이 있으면 댓글로 질문해 주세요. 또한, 번역이 부정확하거나 기타 오류가 있는 경우 PM에게 편지를 보내주시면 수정해 드리겠습니다. 감사하겠습니다. 원래의. ArrayList dstList = new ArrayList (srcList.size()); Collections.copy(dstList, srcList);
코멘트
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION