자바

[Java] 컬렉션 List (ArrayList, Vector, LinkedList)

juhoyang 2024. 10. 11. 16:54

컬렉션이 필요한 이유

- Array는 고정된길이를 가지고 있어 선언 이후에 길이 수정이 안되고 중간에 값을 끼워놓기 번거롭다.

 

예시

- 기존 Array에 1~2 사이에 25를 넣고 싶은경우

- 1개더 큰 Array생성 > 앞부분(0~1) 복사 > 25넣기 > 뒷부분 복사(2~6)

- 배열을 새로 생성해야하고 번거롭다. 

 

컬렉션 (Collections)

- 데이터들의 집합

- java에서는 여러 데이터 구조들을 제공하여 사용자는 비즈니스 로직에만 집중 할 수 있다.

- java제공 : List, Set, Queue, Map

 

List

- 컬렉션을 상속 받은 인터페이스

- 순서가 있는 집합

- 어디에 자료가 삽입되는지 정밀하게 제어 가능

- 중복요소 허용, 위치값 접근 가능

 

- 일반 리스트 선언

 

 

List타입 안전성

- 리스트는 타입을 설정하지 않고 선언 가능하다.

 

- 특정 자료형만 받고싶으면 자료형을 기입해 일반화를 해야한다.

 

 

List 불변성, 가변성

String, wrapper클래스들은 불변성을 가짐 -> 인스턴스를 만든 순간 값을 바꿀 수 없음

 

불변성 리스트

- 기본적으로 List는 수정을 허용하지 않는다.

- List.of(), Map.of() 로 생성된 리스트에 해당

 

예) List.of로 생성한 List에 값을 추가해보기

- UnsupportedOperationException 에러발생

 

가변성 리스트

- 리스트를 상속받은 클래스로 수정을 허용한다.

- ArrayList, LinkedList, Vector

 

 

 

예) ArrayList선언 (LinkedList, Vector 동일 )

 

데이터 구조

ArrayList, Vector

- 배열과 동일함

- 특정 요소를 찾기는 쉽지만 삽입, 삭제가 번거로움

 

그림예시

 

LinkedList

- 요소의 삽입 삭제가 쉽지만 특정 위치의 요소에 접근하는건 처음부터 찾아야 함

 

그림예시

 

-> 삽입 삭제가 적고 요소를 위치기반으로 접근해 사용하고 싶다면  ArrayList, Vector 사용

 

ArrayList Vector 차이

- Vector는 자바 1 에서부터 ArrayList는 자바 1.2부터 생김 

 

클래스의 메소드들을 보면

왼쪽 Vector.java, trimToSize

- Vector는 대부분의 메서드에  synchronized 처리가 되어있다.

 

- synchronized는 해당 메서드는 한번에 하나의 스레드만 사용가능하도록한다. 

- 즉 Vector클래스의 인스턴스가 여러 스레드 사이에 공유될 때스레드 중 하나만이 해당 메서드를 이용할수 있고 나머지는 대기해야한다. 

- 스레드 한개 혹은 다수가 접근이 되어도 안정적으로 처리가능하다. 

- Vector 는 synchronized 메서드로 스레드에 안전하다. (여러 스레드에서 데이터를 공유할때)

- 하지만 동기화 메서드로 성능이 낮아질 수 있다.

 

리스트 데이터 추가, 삭제, 변경

추가

- add("대상") or add(넣을주소, "대상")

- 중복을 허용하기 때문에 같은 대상을 넣을 수 있다.

 

- addAll(리스트) or addAll(넣을주소, 리스트) : 리스트에 있는 모든 요소를 넣는다.

 

삭제

- remove(삭제위치), remove(요소)

 

변경

- set(위치, 바꿀값)

 

반복문 활용

- 기본적으로 for문으로 많이 활용한다.

- List의 경우 Iterator을 제공한다. 보통 while문과 함께 사용하는데 안에 있는 값들을 하나씩 꺼내 사용가능하다.

 

- 특정 대상을 리스트에서 제거 하고싶다면 Iterator을 사용하는게 좋다.

 

반복문을 사용하다 보면 만나는 ConcurrentModificationException에러 

- 리스트를 for each문에서 삽입, 삭제할 때 순환점에 수정이 있으면 에러 발생한다.

 

for문 수정 

- 일반적인 for문으로 수정했을 때 위와 같이 B가 하나 남는다. 

- 이유는 i가 1일 때 index : 1번에 B를 만나고 해당 인덱스 값을 삭제하는데 이때 리스트 삭제로 크기가 3개로 줄어 {"A", "B", "C"} 가되는데 i++ 가 되고나서 index가 2인 C를 조회 하기 때문에 하나의 요소가 건너 뛰어진다.

 

Iterator 사용

- 정상적으로 삭제된 것을 볼수 있다.

 

=> List를 루프만 한다면 대부분은 for each문을 사용하는게 좋고 삭제, 삽입이 있는경우 Iterator을 쓰는게 좋다.

 

정렬

- Collections.sort를 이용해 오름차순으로 정렬 가능하다.

 

클래스 리스트 정렬

- Student.java

 

- main 메서드를보면

- Collections를 그대로 쓰려면 에러가 나는데 해당클래스가 Comparable을 상속 받아야 한다고 한다.

- 실제로 해당 소스는 어떤 것을 기준으로 정렬할지 정의하지 않았다.

 

Collections.sort 소스

 

참고로 위에 적용했던 String, Integer모두 해당 인터페이스를 상속 받았다.

 

Student.java에서 정렬을 적용하기 위해 상속을 받으면

- compareTo를 오버라이딩 해야하는데 해당 return값이 0이면 자리를 안바꾸고 양수면 자리를 바꾸는 역할을 한다.

- 먼저 Integer.compare은 첫번째값과 두번째 값을 비교해서 두번째가 크면 -1, 같으면 0, 반대면 1을 리턴한다.

 

main 메서드 결과를 보면 

- 오름차순으로 정렬된것을 볼수 있다. 만약 반대로 하고 싶다면  compareTo 매서드에 compare의 순서를 바꾸면 된다.

 

 

위와 같이 개발한 상태에서 때에 따라 다른 정렬을 하고 싶다면 어떻게 해야할까?

 

Collections의 오버로딩 된 메서드 중 Comparator(비교자)을 같이 받는 메서드가 있는데 해당 메서드를 활용해서  

Comparator를 상속받은 클래스를 만든다.

 

DescSort.java : Comparator을 상속 받은 클래스

- Student의 id기준으로 정렬을 진행한다.

 

사용을 해보면

- 정상작동을 확인할수 있다.

 

ArrayList 클래스에도  Comparator(비교자)을 같이 받는메서드가 있어 활용가능하다.


문서 참고

https://docs.oracle.com/en/java/javase/23/docs/api/java.base/java/util/List.html

 

 

List (Java SE 23 & JDK 23)

An ordered collection, where the user has precise control over where in the list each element is inserted. The user can access elements by their integer index (position in the list), and search for elements in the list. Unlike sets, lists typically allow d

docs.oracle.com