ABOUT

성능과 운영 안정성을 함께 끌어올리는 개발자입니다.

92% Positional Error Reduction
79% p95 Latency Improvement
90%+ Long Tasks Reduction

2022.02 · 한국장학재단

우수 멘티

한국장학재단 사회 리더 대학생 멘토링 IT

2022.10 · 동작구청

우수 인재상

동작구청 우수 SW 인재

2025.05 · (주) 그랩

프로그래밍 우수상

(주) 그랩 우수 프로그램 개발

2025.05 · AWSKRUG

AWS한국사용자모임 발표

AI agent 스크립트 튜닝 관련 발표

ComputerScience

Development

Engineering

Trouble Shooting

GUESTBOOK

첫 마음부터
함께 나누는 온기

방명록 작성하러 가기

SUBSCRIBE

최신소식을
편하게 만나보세요.

ArrayList

 

정의
내부는 배열(Array)이며, 크기가 유동적으로 확장되는 동적 배열 기반의 자료구조입니다.

실무에서 “List” 라고 하면 대부분 ArrayList를 의미하며, List 인터페이스의 대표 구현체로 배열의 속도와 List의 편의성을 섞은 구조입니다.

하지만 내부는 결국 배열이므로, shift와 resize 비용을 이해해야 한다.”

내부 구조는 결국 배열이기 때문에 인덱스 접근(get/set)이 매우 빠르고, 순회 성능도 좋은 편입니다.

대신 “배열의 한계”도 그대로 가집니다. 특히 중간 삽입/삭제가 많으면 요소 이동(shift)이 발생해 비용이 커질 수 있습니다.

특징
랜덤 접근(O(1))순회 성능입니다.

ArrayList는 내부 배열에 연속적으로 저장되므로 CPU 캐시에 유리합니다. 그래서 반복문으로 훑는 작업(검색/필터/매핑)이 빠르게 동작합니다.

반면, 리스트 중간에 요소를 넣거나 빼면 뒤쪽 요소들을 한 칸씩 움직여야 하므로 중간 삽입/삭제는 O(n)입니다.

💡 TIP

“ArrayList가 빠르다”는 건 보통 get/set/순회가 빠르다는 뜻입니다.
삽입/삭제가 많은 워크로드라면, 자료구조보다 먼저 데이터 접근 패턴을 다시 봐야 합니다.

 

시간복잡도
끝은 빠르고, 중간은 비쌉니다.
연산 시간 설명
get / set O(1) 인덱스로 바로 접근(배열 기반)
add (끝) O(1) 평균 대부분 뒤에 붙이기만 함 (단, resize 발생 시 비용 증가)
add/remove (중간) O(n) 뒤 요소들을 shift 해야 함
contains/search O(n) 값을 찾으려면 순회 필요 (정렬되어 있으면 별도 전략 가능)
내부 동작
ArrayList는 꽉 차면 더 큰 배열을 새로 만들고 복사합니다.

ArrayList는 내부 배열이 가득 차면 자동으로 용량을 늘립니다. 이때는 새 배열을 만들고 기존 요소를 통째로 복사하기 때문에 그 순간만큼은 O(n)이 됩니다.

하지만 resize는 매번 발생하지 않도록 설계되어 있어, 전체적으로는 add가 평균 O(1)으로 동작합니다(Amortized O(1)).

💡 TIP / 참고사항

원소 수가 대략 예측 가능하면, 초기 용량(capacity)을 지정해 resize 횟수를 줄일 수 있습니다.
예: new ArrayList<>(1000) 처럼 미리 크게 잡아두면 대량 add에서 성능이 안정됩니다.

 

실전 예시
“조회/순회 중심 로직”에서 효과적입니다.
import java.util.*;

public class Example {
	public static void main(String[] args) {
    	// 1) 기본 생성 (처음 capacity는 내부적으로 관리됨)
    	List<String> names = new ArrayList<>();
    	// 2) 끝에 추가 (평균 O(1))
    	names.add("A");
    	names.add("B");
        names.add("C");
        // 3) 인덱스 접근 O(1)
        String second = names.get(1);// "B"
        // 4) 순회 (캐시 친화적이라 빠른 편) 
        for (String n : names) {
        	System.out.println(n);
        } 
        // 5) 중간 삽입/삭제는 shift 발생 (주의)
        names.add(1, "X"); // [A, X, B, C]
        names.remove(2); // [A, X, C] 
   }
}

👍 GOOD

  • 인덱스 기반 처리(정렬/DP/투포인터)가 필요할 때
  • 데이터를 자주 읽고(조회), 순회가 많을 때
  • append 중심(끝 추가)으로 데이터가 쌓일 때

👎 BAD

  • 앞/중간 삽입·삭제가 매우 잦은 워크로드
  • 크기 변동이 크고 resize 비용이 민감한 경우 (대량 add 반복)
  • 동시성 환경에서 동기화 없이 공유 List로 쓰는 경우

💡 TIP / 참고사항

멀티스레드 환경에서 ArrayList를 공유하면 안전하지 않습니다.
필요하다면 Collections.synchronizedList(), CopyOnWriteArrayList 같은 대안을 고려해야 합니다(상황에 따라 비용이 큼).

 

✅ 핵심 요약

  • ✔️ ArrayList는 동적 배열 기반 List로, get/set/순회가 빠르다.
  • ✔️ 끝 삽입은 평균 O(1)이지만, resize 시 배열 복사 O(n)이 순간적으로 발생한다.
  • ✔️ 중간 삽입/삭제는 shift 때문에 O(n)이라, 워크로드 패턴에 맞춰 선택해야 한다.
728x90