Java

Collection Framework - ArrayList 정리

OneMoreThing 2024. 1. 8. 20:28

ArrayList? 

ArrayList는 기존의 배열의 단점을 보완한 자료구조(data structure)이다. 기존의 배열은 어떤 단점이 존재하길래 ArrayList가 등장한 것일까.


1. 기존 배열의 단점

알고리즘 문제풀이를 하거나 프로젝트를 진행하다보면 입력의 개수를 정확히 알기 어려운 경우가 빈번하다. 이런 경우 기존의 배열을 사용하는 것은 굉장히 불편하다. 사이즈를 초과한 입력이 들어오는 것을 방지하기 위해 배열의 길이를 넉넉히 잡자니 메모리 낭비가 심해지고, 그렇다고 짧게 잡았다가 overflow가 발생하게 되면 사이즈를 늘린 새로운 배열에 값을 옮기는 작업을 해주어야한다. 이런 문제를 해결하기 위해 Collection Framework 는 ArrayList를 제공한다.


2. ArrayList의 특징 및 장점

기존의 배열의 단점을 보완한 ArrayList는 어떤 특징과 장점을 가지고 있을까?

1. 동적 배열 : 크기가 가변적이다!
2. 다양한 메소드 제공

 

동적 배열이라는 장점은 개발 과정에서 온몸으로 체감할 수 있을만큼 강력하다! 배열의 사이즈라는 사소하지만 무시할 수 없는 요소에 대한 걱정을 내려놓고 다른 곳에 집중할 수 있기 때문에 능률을 올려준다. 또한 다양한 메소드를 제공하기 때문에 편리하게 요소를 추가, 조회, 제거를 할 수 있다.

 

이렇게 편리한 ArrayList는 어떻게 사용해야할까?

 

3. ArrayList의 사용방법

  1. import java.util.ArrayList;
    ArrayList를 사용하기 위해선 먼저 위의 패키지를 import 해줘야한다.
  2. 참조형 데이터 타입 : 기본형 변수가 아닌 참조형 변수 사용
    ArrayList 객체를 생성할 때는 primitive type 이 아닌 참조형 변수(Wrapper 클래스 / 임의의 클래스)를 활용해야한다.
    ---------------------------------------------------------------------------------
    틀린 예) ArrayList<int> intList = new ArrayList<>(); // 오류 발생! int 로 선언하면 안됨!
    옳은 예) ArrayList<Integer> intList = new ArrayList<>(); 
    ---------------------------------------------------------------------------------
  3. 요소 추가 : add() 메소드
    요소를 추가하기 위해선 add() 메소드를 사용한다.
    ---------------------------------------------------------------------------------
    intList.add(1); // 1을 원소로 추가한다. 요소들은 순서대로 저장된다.
    ---------------------------------------------------------------------------------
  4. 요소 삭제 : remove() 메소드
    특정 위치에 있는 요소를 제거하기 위해선 remove() 메소드를 사용한다.
    요소를 삭제하고 생긴 빈공간은 뒤에있는 요소들을 앞으로 이동시켜 빈공간을 메우게 된다.
    ---------------------------------------------------------------------------------
    intList.remove(0); // 0번에 있는 요소를 제거한다.
    ---------------------------------------------------------------------------------
  5. 요소 조회 : get() 메소드
    특정 위치에 있는 요소를 조회하기 위해선 get() 메소드를 사용한다.
    ---------------------------------------------------------------------------------
    intList.get(0); 0번에 있는 요소를 return 한다.
    ---------------------------------------------------------------------------------
    #Tip : 포함된 모든 요소를 출력할 때는 향상된 for 문을 활용하면 간결하게 코드를 작성할 수 있다.
    for(int elem : intList){ // intList 안의 모든 요소를 콘솔창에 출력
        System.out.println(elem); 
    }
    ---------------------------------------------------------------------------------
  6. 현재 저장된 요소의 개수 조회 : size() 메소드
    현재 어레이리스트 안에 저장된 요소들을 파악하기 위해선 size() 메소드를 사용한다. 기존의 배열에서 length 와 같은 역할을 한다.
    ---------------------------------------------------------------------------------
    intList.size(); 
    ---------------------------------------------------------------------------------

4. ArrayList은 완벽할까?

과연 ArrayList는 장점만 존재할까? 물론 그렇지 않다. 이는 자료구조를 배우면 자세히 알 수 있다. 간략하게 설명하면 다음과 같다.

ArrayList가 가변적인 사이즈를 갖는 것은 라이브러리에서 최적화된 메소드를 제공해주기 때문에 가능한 것이다.

1. 초기 사이즈 (DEFAULT_CAPACITY) : ArrayList가 정의된 클래스를 추적해 들어가보면 초기 사이즈가 상수로 10인 것을 볼 수 있다. 만약 이를 초과해서 input 이 들어온다면 사이즈를 늘리고 새롭게 데이터를 옮기는 작업을 우리가 모르게 자동적으로 해주는 것이다. 즉, 사이즈를 늘리는 과정에서 속도 저하가 발생하게 된다.

2. remove() : ArrayList 내부의 요소를 제거하게 되면 자동적으로 뒤에 있는 요소들을 앞으로 한칸씩 이동시키는 작업을 처리해준다. 이때 최악의 경우는 언제일까? 바로 맨 앞에 있는 요소를 제거하는 경우이다. 길이가 n인 어레이리스트에서 맨 0번째 요소를 제거하게 되면 n-1번의 이동이 생기게 된다. 어레이리스트가 많은 요소를 가질수록 속도 저하는 심해질 것이다.

 

5. 그럼에도 불구하고 ArrayList를 사용하자

그럼에도 불구하고 ArrayList를 적극활용하도록 하자. 이미 수 많은 개발자들이 최적화를 끝내놓은 라이브러리이다. 속도 이슈를 생각할 정도의 큰 규모의 프로젝트라면 신중해야겠지만, 코딩테스트를 위한 알고리즘 문제풀이나 규모가 작은 프로젝트에서는 ArrayList를 사용하는 것이 이득이다. 고집을 부리며 배열을 사용하고 불편함을 이어가겠다면 말리지 않겠지만, 라이브러리를 능수능란하게 다루는 것도 개발자의 필수 역량이라 생각한다.