본문 바로가기
웹프로그래밍/Java

Java Collections

by Seras 2017. 11. 22.
반응형

다음은 Stackoverflow에서 논의되고 논의 된 Java 콜렉션에서 가장 많이 사용되는 질문입니다. 이러한 질문을보기 전에 클래스 계층 구조 다이어그램 을 보는 것이 좋습니다 .

1. ArrayList를 통해 LinkedList를 사용하는 경우는 언제입니까?

1. ArrayList를 통해 LinkedList를 사용하는 경우는 언제입니까?

ArrayList 는 기본적으로 배열입니다. 그 요소는 색인을 통해 직접 액세스 할 수 있습니다. 그러나 배열이 꽉 찬 경우 새로운 배열을 할당하고 새 배열로 모든 요소를 ​​이동하는 데 O (n) 시간이 걸립니다. 또한 요소를 추가하거나 제거하면 배열의 기존 요소를 이동해야합니다. ArrayList를 사용하는 것이 가장 불리 할 수 ​​있습니다.

LinkedList 는 이중 연결 목록입니다. 따라서 중간에있는 요소에 액세스하려면 목록의 처음부터 검색해야합니다. 반면에 LinkedList에서 요소를 추가하거나 제거하는 것은 목록을 로컬에서만 변경하기 때문에보다 신속합니다.

요약하면, 시간 복잡성 비교 의 최악의 경우는 다음과 같습니다.

                   | Arraylist | LinkedList
 ------------------------------------------
 get(index)        |    O(1)   |   O(n)
 add(E)            |    O(n)   |   O(1)
 add(E, index)     |    O(n)   |   O(n)
 remove(index)     |    O(n)   |   O(n)
 Iterator.remove() |    O(n)   |   O(1)
 Iterator.add(E)   |    O(n)   |   O(1)

실행 시간에도 불구하고 큰 목록의 경우 특히 메모리 사용을 고려해야합니다. 에서 LinkedList의 모든 노드는 이전 및 다음 노드를 연결하는 적어도 두 개의 여분의 포인터가 필요합니다; 반면에 ArrayList의 요소의 배열이 필요하다.


2. 컬렉션을 반복하면서 요소를 제거하는 효율적인 동등

iterating하는 동안 컬렉션을 수정하는 유일한 방법은 Iterator를 사용하는 것 입니다. remove () . 예를 들어,

Iterator<Integer> itr = list.iterator();
while(itr.hasNext()) {
   // do something
   itr.remove();
}

가장 빈번하게 잘못된 코드가 하나 있습니다.

for(Integer i: list) {
  list.remove(i);
}

당신은 얻을 것이다 ConcurrentModificationException를 위의 코드를 실행하여. 이는 iterator가 for 문 에서 생성 되어 목록을 트래버스하지만 동시에 Iterator에 의해 목록이 변경되기 때문 입니다. remove () . Java에서 "한 스레드가 다른 스레드가 반복하는 동안 컬렉션을 수정하는 것은 일반적으로 허용되지 않습니다."

3. 목록을 int []로 변환하는 방법?

가장 쉬운 방법은 Apache Commons Lang 라이브러리 에서 ArrayUtils 를 사용하는 것 입니다.

int[] array = ArrayUtils.toPrimitive(list.toArray(new Integer[0]));

JDK에는 지름길이 없습니다. 목록을 사용할 수는 없습니다 . toArray () 는 List 를 변환하므로~ 정수 [] . 올바른 방법은 다음과 같습니다.

int[] array = new int[list.size()];
for(int i=0; i < list.size(); i++) {
  array[i] = list.get(i);
}

4. int []를 List로 변환하는 방법은 무엇입니까?

가장 쉬운 방법은 아래와 같이 여전히 Apache Commons Lang 라이브러리 에서 ArrayUtils 를 사용하는 것입니다.

List list = Arrays.asList(ArrayUtils.toObject(array));

JDK에서는 지름길도 없습니다.

int[] array = {1,2,3,4,5};
List<Integer> list = new ArrayList<Integer>();
for(int i: array) {
  list.add(i);
}

5. 컬렉션을 필터링하는 가장 좋은 방법은 무엇입니까?

다시 말하지만, Guava 또는 Apache Commons Lang 과 같은 써드 파티 패키지를 사용 하여이 기능을 fullfil 할 수 있습니다. 둘 다 제공하는 필터 () (메소드 Collections2 구아바 및 예약 CollectionUtils 아파치 참조). 필터 () 메소드는 소정의 일치 요소 반환 술어 .

JDK에서는 일이 더 어려워진다. 좋은 소식은 Java 8에서 Predicate 가 추가된다는 것입니다. 하지만 지금은 Iterator 를 사용 하여 전체 컬렉션을 트래버스해야합니다.


Iterator<Integer> itr = list.iterator();
while(itr.hasNext()) {
   int i = itr.next();
   if (i > 5) { // filter all ints bigger than 5
      itr.remove();
   }
}

물론 새로운 인터페이스 Predicate를 도입하여 Guava와 Apache의 방식을 모방 할 수 있습니다 . 그것은 또한 가장 진보 된 개발자가 할 수있는 것일 수도 있습니다.

public interface Predicate<T> {
   boolean test(T o);
}
 
public static <T> void filter(Collection<T> collection, Predicate<T> predicate) {
    if ((collection != null) && (predicate != null)) {
       Iterator<T> itr = collection.iterator();
          while(itr.hasNext()) {
            T obj = itr.next();
            if (!predicate.test(obj)) {
               itr.remove();
            }
        }
    }
}

그런 다음 다음 코드를 사용하여 컬렉션을 필터링 할 수 있습니다.

filter(list, new Predicate<Integer>() {
    public boolean test(Integer i) { 
       return i <= 5; 
    }
});

6. 목록을 세트로 변환하는 가장 쉬운 방법은 무엇입니까?

동등한 정의 방법에 따라 이렇게하는 방법에는 두 가지가 있습니다 . 첫 번째 코드는 목록을 HashSet에 넣습니다 . 복제는 주로 hashCode ()에 의해 식별됩니다 . 대부분의 경우 작동합니다. 그러나 비교 방법을 지정해야하는 경우 자신의 비교자를 정의 할 수있는 두 번째 코드를 사용하는 것이 좋습니다.

Set<Integer> set = new HashSet<Integer>(list);
Set<Integer> set = new TreeSet<Integer>(aComparator);
set.addAll(list);

7. ArrayList에서 반복되는 요소를 제거하려면 어떻게해야합니까?

이 질문은 위의 질문과 상당히 관련이 있습니다. ArrayList

에있는 요소의 순서를 신경 쓰지 않는다면 , 똑똑한 방법은 목록을 집합에 넣어 중복을 제거한 다음 다시 목록으로 옮기는 것입니다. 여기에 코드가있다.

ArrayList** list = ... // initial a list with duplicate elements
Set<Integer> set = new HashSet<Integer>(list);
list.clear();
list.addAll(set);

순서를 신경 쓰면 표준 JDK에있는 LinkedHashSet에 목록을 넣어 순서를 유지할 수 있습니다

8. 정렬 된 컬렉션

Java로 정렬 된 콜렉션을 유지하는 데는 두 가지 방법이 있습니다. 그것들 모두는, 자연 순서 부에 또는 지정된 콤퍼레이터에 의한 콜렉션을 제공합니다. 하여 자연 순서 , 당신은 또한 구현해야 대등 요소의 인터페이스를.

  1. 컬렉션 . sort () 는 List를 정렬 할 수 있습니다. javadoc에 지정된대로이 정렬은 안정적 이며 n log (n) 성능을보장합니다.
  2. PriorityQueue 는 순서화 된 큐를 제공합니다. PriorityQueue 와 컬렉션 의 차이점. sort () 는 PriorityQueue 가 항상 순서 대기열을 유지하지만 대기열에서 head 요소 만 가져올 수 있다는 점입니다. PriorityQueue 와 같은 요소에 무작위로 액세스 할 수 없습니다. get (4) .
  3. 컬렉션에 중복이 없으면 TreeSet 이 다른 선택입니다. PriorityQueue 와 동일하게 모든 순서로 정렬 된 집합을 유지 관리합니다. TreeSet 에서 가장 낮은 요소 와 가장 높은 요소를 가져올 수 있습니다 . 하지만 여전히 요소에 임의로 액세스 할 수는 없습니다.
  4. 짧은 컬렉션 . sort () 는 일회성 정렬 목록을 제공합니다. PriorityQueue 와 TreeSet 은 요소의 인덱스 된 액세스가없는 비용으로 항상 순서가 지정된 콜렉션을 유지합니다.

9. Collections.emptyList() vs new instance

같은 질문은 emptyMap () 과 emptySet () 에도 적용됩니다 .

두 메서드 모두 빈 목록을 반환하지만 컬렉션을 반환합니다 . emptyList () 는 불변 인리스트를 리턴합니다. 즉, " 빈 "목록에 새 요소를 추가 할 수 없습니다 . 배경에서 컬렉션의 각 호출 . emptyList ()는 실제로 빈리스트의 새로운 인스턴스를 생성하지 않습니다. 대신 기존 빈 인스턴스를 다시 사용합니다. 디자인 패턴에 친숙한 싱글 톤 이라면 무엇을 의미하는지 알아야합니다. 따라서 자주 호출하면 성능이 향상됩니다.


10 Collections.copy

소스 목록을 대상 목록에 복사하는 방법에는 두 가지가 있습니다. 한 가지 방법은 ArrayList 생성자 를 사용하는 것입니다.

ArrayList<Integer> dstList = new ArrayList<Integer>(srcList);

다른 하나는 컬렉션 을 사용하는 것 입니다 . copy () (아래). 때문에 우리의 자바 독에있는 소스 목록으로 적어도 한 목록을 할당, 첫 번째 줄을 참고 컬렉션 , 그것은 말한다 대상 목록이 적어도 한 소스 목록으로해야합니다.

ArrayList<Integer> dstList = new ArrayList<Integer>(srcList.size());
Collections.copy(dstList, srcList);

두 가지 방법 모두 얕은 복사본입니다. 그렇다면 이 두 가지 방법 의 차이점 은 무엇 입니까?

첫째, 컬렉션 . 복사 () 의 용량 재 할당되지 않습니다 dstList을 경우에도 dstList가 모두 포함 할 수있는 충분한 공간이없는 srcList 요소를. 대신 IndexOutOfBoundsException 을 던집니다 . 어떤 이점이 있는지 의문을 가질 수도 있습니다. 한 가지 이유는 메서드가 선형 시간에 실행된다는 것을 보장하기 때문입니다. 또한 ArrayList 의 생성자에 새 메모리를 할당하지 않고 배열을 다시 사용할 때 적합합니다 .

컬렉션 . copy () 는 List 를 소스와 대상으로 만 수락 할 수 있지만 ArrayList 는 Collection 을 매개 변수로 받아들이 므로 더욱 일반적입니다.

반응형

'웹프로그래밍 > Java' 카테고리의 다른 글

Java exceptions  (0) 2017.11.22
Java Maps  (0) 2017.11.22
Java Strings  (0) 2017.11.22
Java Array  (0) 2017.11.22
Java HashMap의 자주 사용되는 메소드  (0) 2017.11.22