본문으로 바로가기

[Java] 리스트 컬렉션 (List Collection)

category Language/Java 2020. 1. 23. 03:08

1. List란?

리스트는 배열과 비슷한 자바의 자료형으로 배열보다 편리한 기능을 많이 가지고 있다.

배열은 크기가 정해져있지만 리스트는 동적으로 자료형의 갯수가 변할 수 있다.

 

객체를 인덱스로 관리하기 때문에 List 컬렉션에 객체를 추가하면 자동 인덱스가 부여된다.

인덱스는 객체를 검색, 삭제할 때 사용한다.

List 컬렉션은 객체 자체를 저장하는 것이 아닌 객체의 번지를 참조한다.

동일한 객체가 저장 가능하며 이 경우에는 동일한 객체의 번지를 참조한다.

null도 저장할 수 있다.

 

List 자료형에는 ArrayList, Vector, LinkedList까지 List 인터페이스를 구현한 자료형이 있다.

 

2. 메서드

리스트 인터페이스에는 기본적인 메서드가 추가되어 있다.

  • 추가
    • add : 요소 추가
  • 검색
    • contain : 해당 요소 포함 유무 확인
    • get : 해당 인덱스의 값 조회
    • size : 리스트의 크기
  • 삭제
    • remove : 요소 삭제
    • clear  : 모든 요소 지우기

List 컬렉션 인터페이스를 상속해서 구현하는 클래스는 해당 기능을 오버라이드 해야한다.

간단한 예제

// String 객체를 관리하는 ArrayList 생성 
List<String> list = new ArrayList(); 

// String 객체 저장 
list.add("Hello World"); 

// null 저장 
list.add(null);

// 동일한 String 객체를 갖고 있는지 검색
boolean isFindValue = list.contains("Hello World");

// 인덱스 값을 이용하여 객체 삭제 
list.remove(0); 

// List에 저장된 모든 객체를 얻어서 콘솔 창에 출력
for(String value : list) { 
	System.out.println(value); 
}

3. ArrayList 클래스

ArrayList는 List 컬렉션 인터페이스를 구현한 클래스이다. List 컬렉션처럼 인덱스로 객체를 관리한다. 

일반 배열과 ArrayList는 인덱스로 객체를 관리한다는 점에서 동일하지만,

크기를 동적으로 늘릴 수 있다는 점에서 차이점이 있다.

 

배열은 처음 생성할 때 고정 크기를 지정하며, 사용 중에 크기를 변경할 수 없다.

만약 크기를 늘려야 한다면 새로 배열을 선언해야 한다는 단점이 있다.

매번 바뀌는 요구사항에 따라 동적으로 유연하게 처리해야 한다면, 배열보다는 ArrayList를 사용하는 것이 적절하다.

 

ArrayList는 내부에서 처음 설정한 저장 용량(capacity)가 있다.

설정한 저장 용량 크기를 넘어서 더 많은 객체가 들어오게 되면, 자동적으로 저장 용량이 늘어난다.

 

// String 객체를 관리하는 ArrayList 생성 
// 기본 저장 용량은 10
List<String> list = new ArrayList<>(); 

// 저장 용량을 100으로 설정해서 String 객체를 관리하는 ArrayList 생성 
List<String> list = new ArrayList<>(100);

List 컬렉션 인터페이스는 제네릭 타입이다.

이전 버전의 호환을 위해서 타입 파라미터 없이 아래 코드처럼 ArrayList를 생성할 수 있다.

// java 4 이전에서 ArrayList 생성 방법
// 타입 파라미터를 지정하지 않았으므로 IDE에서 경고를 표시합니다. 
List list = new ArrayList();

하지만, 이렇게 선언하게 되면 어느 객체든 저장할 수 있는 ArrayList가 되어 버린다.

Object 클래스는 모든 클래스의 조상(부모) 클래스이기 때문에 객체가 저장될 때 Object 타입으로 변환되어 저장된다.

 

모든 종류의 객체를 저장할 수 있다는 것은 장점이지만,

ArrayList 내부에 있는 객체(Object)를 꺼내서 사용할 때 실제 타입으로 변환해야 하므로

실행 성능에 좋지 못한 영향을 끼치게 된다.

 

ArrayList에서 특정 인덱스의 객체를 제거하게 되면,

제거한 객체의 인덱스부터 마지막 인덱스까지 모두 앞으로 1칸씩 앞으로 이동한다.

객체를 추가하게 되면 1칸씩 뒤로 이동하게 된다.

인덱스 값을 유지하기 위해서 전체 객체가 위치가 이동한다.

 

이처럼 객체 삭제와 삽입이 빈번하게 일어나는 곳에서 ArrayList를 사용하지 않는 것이 좋다.

이러한 경우에는 LinkedList를 사용하는 것이 좋다. 

ArrayList는 인덱스가 있으므로 객체 검색, 맨 마지막에 객체 추가 등에서 좋은 성능을 발휘한다.

 

  • ArrayList : 객체 검색, 맨 마지막 인덱스에 객체 추가에 좋은 성능을 발휘함
  • LinkedList : 객체 삽입 및 삭제에 좋은 성능을 발휘함
// ArrayList 객체 생성
List<String> list = new ArrayList<>();

// 객체 추가
list.add("Hello");
list.add("gglee");

// 객체 총 개수
int size = list.size();

// 동일한 객체 있는지 검색
boolean isFindValue = list.contains("gglee");

// 인덱스에 위치하는 객체 값 얻기
String str = list.get(0);

// 인덱스를 이용하여 객체 삭제
list.remove(0);

고정된 객체들로 구성된 List를 생성하는 방법도 있다.

Arrays 클래스의 정적 메서드 asList()를 이용하면 된다.

이 정적 메서드를 이용하여 생성된 ArrayList는 앞에서 설명한 ArrayList와는 다른 클래스이다.

이 ArrayList는 추가(add), 삭제(remove) 기능을 제공하지 않는다.

// String 객체를 관리하는 ArrayList 생성
List<String> list = Arrays.asList("hello", "gglee", "java");

// UnsupportedOperationException 에러 발생
// list.add("hello");

// UnsupportedOperationException 에러 발생
// list.remove(1);

4. Vector 클래스

Vector는 ArrayList와 동일한 내부 구조를 가지고 있다.

Vector 객체를 생성하기 위해서는 저장할 타입을 지정해야 한다. 

ArrayList와 차이점으로는 Vector 클래스는 동기화된(synchronized) 메서드로 구성되어 있다.

그렇기 때문에 멀티 스레드 환경에서 안전하게 객체를 추가, 삭제할 수 있다.

즉, 스레드에 안전하다(Thread Safe)라고 말합니다.

다만 동기화되어 있기 때문에 ArrayList 보다는 객체를 추가, 삭제하는 과정은 느릴수 밖에 없다.

안전성을 추구하는데 있어서 속도를 포기한 트레이드 오프(trade off)이다.

 

Vector 클래스의 add() 동기화 메서드

예제코드

// String 객체를 관리하는 Vector 객체 생성 
List<String> list = new Vector<>(); 

// 객체 추가 
list.add("hello"); 

// 객체 제거 
list.remove(0);

5. LinkedList 클래스

LinkedList는 List 구현 클래스이다. 내부 구조는 ArrayList와 다르다. 

ArrayList에는 내부 배열에 객체를 저장해서 인덱스로 관리하지만,

LinkedList는 인접 참조를 링크해서 체인처럼 관리한다.

그렇기 때문에 LinkedList에서 특정 인덱스의 객체를 제거하게 되면,

제거되는 인덱스의 앞 뒤 링크만 변경되고 나머지 링크는 변경되지 않는다.

 

ArrayList는 제거되는 인덱스를 기준으로 뒤에 있는 객체가 한칸씩 이동 했었던 점과 차이가 있다.

이러한 차이로 인해서 객체를 삽입, 삭제하는 로직에 있어서 ArrayList보다 LinkedList를 사용할 때 좋은 성능이 나온다.

 

생성예제

// LinkedList 객체 생성
List<String> list = new LinkedList<>();

Vector보다 ArrayList 사용을 권장한다.

참고: https://lelecoder.com/78