컬렉션이 필요한 이유
- 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는 대부분의 메서드에 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
'자바' 카테고리의 다른 글
[Java] 추상 클래스와 인터페이스 (Abstract class, Imterface) (0) | 2024.10.10 |
---|---|
[Java] 상속 (Inheritance) (0) | 2024.10.04 |
[Java] Array 와 ArrayList (1) | 2024.10.04 |
[Java] Date 타입 (LocalDate, LocalDateTime, LocalTime) (0) | 2024.10.02 |
[Java] 래퍼 클래스 (0) | 2024.10.02 |