항상 자바의 List를 사용하면서 Collection에 대해서 자세히 알지 못하는게 마음에 걸려서 이번 기회에 정리해보려고 한다.
Collection Framework라고 하면 어렵게 느껴지지만 자료구조를 공부해본 사람이라면 그저 자료구조들을 모아둔 인터페이스와 구현 클래스라고 생각하면 이해하기 쉽다.
위 그림에서 List, Queue, Deque, Set, Map 등은 다른 언어나 자료구조를 통해 한번쯤 접해보았을 것이다.(예를 들어 파이썬의 set이나 dictionary 등)
자바를 사용하면서 최소한 한번쯤은 ArrayList를 사용해보았을텐데, ArrayList는 List 인터페이스를 구현한 클래스이다.
따라서 아래와 같은 코드들은 인터페이스의 다형성을 이용해서 자료구조를 사용하는 것이라고 이해하면 된다.
List<String> arrayList = new ArrayList<>();
Map<String, String> hashMap = new HashMap<>();
자바의 컬렉션 프레임워크의 특징은 다음과 같다.
List, Queue, Set이 상속하고 있는 실질적인 최상위 클래스이다.
다형성을 이용해서 List, Queue, Set를 Collection으로 업캐스팅하여 자료를 삽입, 삭제, 탐색하는 방식으로 사용할 수 있다.
Collection에서 자주 사용되는 메서드는 아래와 같다.
Collection 메서드
List 인터페이스는 ArrayList, LinkedList, Vector 등의 구현체를 가지고 있다.
List 인터페이스를 구현한 ArrayList는 배열과 비슷하지만 큰 차이점을 가지고 있다.
배열은 크기가 고정되어있지만 ArrayList는 크기가 동적으로 변할 수 있다는 점이다.
하지만 인덱스를 통해 데이터에 접근하는 속도는 배열이 ArrayList 보다 빠르다.
배열의 경우 메모리에 연속적으로 나열되어있지만 ArrayList는 주소로 연결되어있는 형태이기 때문에 인덱스를 통한 접근 속도가 배열보다 느리다.
ArrayList 메서드
Arrays.asList()
를 사용해서 배열을 List로 변환할 수 있다.
이때 원본 배열과 List가 동기화되기 때문에(List이지만 길이를 더 늘릴 수도 없다) 이를 방지하려면 새로운 List를 만들어서 값만을 복사해서 사용해야 한다.
Integer[] arr = {1, 2, 3, 4, 5};
List<Integer> list1 = Arrays.asList(arr); // 원본 배열과 List 동기화
List<Integer> list2 = new ArrayList<>(Arrays.asList(arr)); // 원본 배열과 List 동기화 x
arr[0] = 10;
list1.get(0); // list 값 변경: 10
arr[0] = 10;
list2.get(0); // list 값 그대로: 1
Arrays.stream()
을 이용해서도 배열을 List로 변환할 수 있다.
Integer[] arr = {1, 2, 3, 4, 5};
List<Integer> list = Arrays.stream(arr).collect(Collectors.toList());
System.out.println(list3) // [1, 2, 3, 4, 5]
list.toArray(new Integer[arrListSize])
로 List에서 배열로 변환할 수 있다.
이때 새로 생성하는 배열의 크기가 list보다 작으면 자동으로 늘려서 원본 배열의 크기에 맞춰주고, list보다 크면 나머지 인덱스는 null로 채워준다.
Integer[] arr = {1, 2, 3, 4, 5};
List<Integer> list = new ArrayList<>(Arrays.asList(arr));
Integer[] arr2 = list.toArray(new Integer[0]);
Integer[] arr3 = list.toArray(Integer[]::new); // 자바 버전 11 이상