- 1 1. 소개
- 2 2. List란?
- 3 3. List 기본 사용법
- 3.1 List 선언 및 초기화
- 3.2 Adding Elements (add)
- 3.3 요소 추가 (add)
- 3.4 Getting Elements (get)
- 3.5 요소 가져오기 (get)
- 3.6 Updating Elements (set)
- 3.7 요소 업데이트 (set)
- 3.8 Removing Elements (remove)
- 3.9 요소 제거 (remove)
- 3.10 Getting List Size (size)
- 3.11 List 크기 가져오기 (size)
- 3.12 Checking for Element Existence (contains)
- 3.13 요소 존재 여부 확인 (contains)
- 3.14 Summary: List of Frequently Used Basic Operations
- 3.15 요약: 자주 사용되는 기본 연산 목록
- 4 4. List Operation Examples
- 5 4. List 연산 예시
- 6 5. Differences and Usage of ArrayList and LinkedList
- 7 5. ArrayList와 LinkedList의 차이점 및 사용법
- 8 6. List의 고급 사용법
- 9 7. 일반적인 오류와 해결 방법
1. 소개
Java에서 List의 중요성은 무엇인가?
Java 프로그래밍에서 “List”는 매우 자주 등장하는 자료구조입니다. 특히 여러 값을 함께 관리하고자 할 때 배열보다 더 유연하고 사용하기 쉬워 실무에서 높은 가치를 지닙니다.
“List”는 Java Collections Framework의 핵심 인터페이스이며, ArrayList, LinkedList와 같은 다양한 구현 클래스를 통해 여러 상황을 처리할 수 있는 메커니즘을 제공합니다. 데이터를 추가·삭제·검색·수정하는 작업을 직관적으로 수행할 수 있다는 점이 List가 선호되는 이유 중 하나입니다.
이 글의 목적 및 대상 독자
이 글은 초보자를 위한 “Java List”를 기초부터 고급 주제까지 체계적으로 쉽게 설명합니다. 주요 대상 독자는 다음과 같습니다:
- Java를 이제 막 배우기 시작했으며 List 사용 방법이 궁금한 사람
- 배열과 List의 차이를 명확히 이해하고 싶은 사람
- ArrayList와 LinkedList 중 어느 것을 선택해야 할지 고민하는 사람
- 실무에서 List를 사용하기 전에 기본 개념을 복습하고 싶은 사람
이 글을 모두 읽고 나면, List의 기본 개념, 구현 방법, 구체적인 연산을 탄탄히 이해하여 자신 있게 코딩할 수 있게 되는 것이 목표입니다.
다음 장부터는 기본 파트인 “List란 무엇인가?”를 단계별로 설명해 나가겠습니다.
2. List란?
List 개요 및 특성
Java의 “List”는 요소를 순서대로 보관하는 컬렉션 인터페이스입니다. 가장 큰 특징은 요소 추가 순서가 보존된다는 점과 인덱스(0부터 시작)를 사용해 개별 요소에 접근할 수 있다는 점입니다.
List는 Collections Framework의 일부로 제공되며 다음과 같은 특징을 가집니다:
- 중복 요소 허용
- 인덱스를 지정해 요소를 조회·수정·삭제 가능
- 배열과 달리 크기가 고정되지 않아 동적으로 요소 수를 늘리거나 줄일 수 있음
이러한 특성 덕분에 유연한 데이터 조작이 가능하며 실무에서 매우 빈번하게 사용됩니다.
배열과의 차이점
Java에서 배열(int[], String[] 등)도 여러 값을 보관하는 수단이지만, List와는 몇 가지 차이점이 있습니다.
| Comparison Item | Array | List |
|---|---|---|
| Changing number of elements | Not possible (fixed-size) | Possible (can increase/decrease dynamically) |
| Provided functionality | Minimal operations (indexed access, length retrieval) | Rich methods (add, remove, contains, etc.) |
| Type | Can handle primitive types | Object types only (wrapper classes required) |
| Type safety | Arrays checked at compile time | Can strictly specify type with Generics |
이처럼 List는 더 유연하고 기능이 풍부한 컬렉션으로, 많은 상황에서 배열보다 실용적입니다.
List 인터페이스와 구현 클래스
Java에서 List를 사용할 때는 보통 List 인터페이스로 변수를 선언하고, 특정 구현 클래스로 인스턴스를 생성합니다. 대표적인 구현 클래스는 다음과 같습니다:
- ArrayList – 배열과 유사한 구조로 빠른 접근이 가능. 데이터 검색 및 랜덤 액세스에 강점.
- LinkedList – 이중 연결 리스트 구조로 구현. 삽입·삭제가 빠르고, 연산이 빈번한 리스트에 적합.
- Vector – ArrayList와 비슷하지만 스레드 안전성을 제공해 약간 무겁다. 현재는 많이 사용되지 않음.
특별한 이유가 없는 한 ArrayList가 가장 일반적으로 사용됩니다. 이후 성능 비교를 통해 상황에 맞는 클래스를 선택하면 됩니다.
3. List 기본 사용법
이 섹션에서는 Java에서 List를 사용할 때의 기본 연산을 단계별로 설명합니다. 여기서는 ArrayList를 예시로 들어 List의 대표적인 연산들을 소개합니다.
List 선언 및 초기화
먼저 ArrayList를 이용한 List의 기본 선언 및 초기화를 살펴보겠습니다.
import java.util.ArrayList;
import java.util.List;
public class Main {
public static void main(String[] args) {
List<String> fruits = new ArrayList<>();
}
}
It is common practice to declare a variable with the List interface and instantiate it with ArrayList. Generics are used to specify the type to be stored (here, String).
변수를 List 인터페이스로 선언하고 ArrayList로 인스턴스화하는 것이 일반적인 관행입니다. 제네릭을 사용하여 저장할 타입을 지정합니다(여기서는 String).
Adding Elements (add)
요소 추가 (add)
To add elements to a List, use the add() method.
List에 요소를 추가하려면 add() 메서드를 사용합니다.
fruits.add("apple");
fruits.add("banana");
fruits.add("orange");
This adds three elements to the List in sequence. List preserves the order of addition.
이 코드는 세 개의 요소를 순차적으로 List에 추가합니다. List는 추가된 순서를 보존합니다.
Getting Elements (get)
요소 가져오기 (get)
To get an element at a specified index, use get(int index).
지정된 인덱스에 있는 요소를 가져오려면 get(int index)를 사용합니다.
System.out.println(fruits.get(0)); // "apple" will be displayed
Note that indices start from 0.
인덱스는 0부터 시작한다는 점에 유의하세요.
Updating Elements (set)
요소 업데이트 (set)
To update an element at a certain position, use set(int index, E element).
특정 위치의 요소를 업데이트하려면 set(int index, E element)를 사용합니다.
fruits.set(1, "grape"); // The second element "banana" is replaced with "grape"
Removing Elements (remove)
요소 제거 (remove)
You can also remove elements by a specific index or the element itself.
특정 인덱스 또는 요소 자체를 사용하여 요소를 제거할 수도 있습니다.
fruits.remove(0); // Removes the first element
fruits.remove("orange"); // Removes "orange" (only the first match)
Getting List Size (size)
List 크기 가져오기 (size)
The current number of elements can be obtained with the size() method.
size() 메서드를 사용하면 현재 요소 개수를 얻을 수 있습니다.
System.out.println(fruits.size()); // Returns 2, etc.
Checking for Element Existence (contains)
요소 존재 여부 확인 (contains)
To check if a specific element is included in the List, use contains().
특정 요소가 List에 포함되어 있는지 확인하려면 contains()를 사용합니다.
if (fruits.contains("grape")) {
System.out.println("grape is present");
}
Summary: List of Frequently Used Basic Operations
요약: 자주 사용되는 기본 연산 목록
| Operation | Method Example | Description |
|---|---|---|
| Addition | add("element") | Adds to the end |
| Retrieval | get(index) | References an element |
| Update | set(index, new element) | Changes the element at the specified position |
| Removal | remove(index/element) | Removes the specified element |
| Get Size | size() | Gets the number of elements |
| Check Existence | contains("element") | Checks if a specific element exists |
4. List Operation Examples
4. List 연산 예시
In this chapter, we will introduce practical operation examples using Java’s List. There are many situations where you want to process elements in a list sequentially, and here we will cover representative methods using for loop, enhanced for loop, and Stream API.
이 장에서는 Java의 List를 활용한 실용적인 연산 예시를 소개합니다. 리스트의 요소를 순차적으로 처리하고자 하는 상황이 많이 있으며, 여기서는 for 루프, 향상된 for 루프, 그리고 Stream API를 이용한 대표적인 방법들을 다룹니다.
Iteration using a for loop
for 루프를 이용한 반복
The most basic method is to retrieve elements using an index within a for loop.
가장 기본적인 방법은 for 루프 안에서 인덱스를 사용해 요소를 가져오는 것입니다.
List<String> fruits = new ArrayList<>();
fruits.add("apple");
fruits.add("banana");
fruits.add("orange");
for (int i = 0; i < fruits.size(); i++) {
System.out.println(fruits.get(i));
}
This method allows for fine-grained control using the index. For example, it is effective when you want to process only elements at even indices.
이 방법은 인덱스를 활용한 세밀한 제어가 가능합니다. 예를 들어, 짝수 인덱스에 있는 요소만 처리하고 싶을 때 효과적입니다.
Iteration using an enhanced for loop (for-each)
향상된 for 루프 (for-each)를 이용한 반복
If you want to process all elements sequentially without worrying about the index, the enhanced for loop is convenient.
인덱스를 신경 쓰지 않고 모든 요소를 순차적으로 처리하고 싶다면 향상된 for 루프가 편리합니다.
for (String fruit : fruits) {
System.out.println(fruit);
}
The syntax is simple and easy to read, making it one of the most commonly used methods. This is sufficient for simple processing.
구문이 간단하고 읽기 쉬워 가장 많이 사용되는 방법 중 하나가 됩니다. 간단한 처리에는 이것만으로 충분합니다.
Iteration using Lambda Expressions and Stream API
람다식 및 Stream API를 이용한 반복
Since Java 8, you can also use the syntax with Stream API and lambda expressions.
Java 8부터는 Stream API와 람다식을 활용한 구문도 사용할 수 있습니다.
fruits.stream().forEach(fruit -> System.out.println(fruit));
The strength of this notation is that multiple processes can be chained together. For example, you can easily filter and then print elements based on specific criteria.
이 표기법의 강점은 여러 작업을 체인처럼 연결할 수 있다는 점입니다. 예를 들어, 특정 기준으로 필터링한 뒤 바로 출력하는 것이 간편합니다.
fruits.stream()
.filter(fruit -> fruit.contains("a"))
.forEach(System.out::println);
In this example, it prints only fruits that contain “a”. This is especially recommended for those who want to get used to functional style coding.
이 예시에서는 문자열에 “a”가 포함된 과일만 출력합니다. 이는 함수형 스타일 코딩에 익숙해지고 싶은 분들에게 특히 권장됩니다.
Choosing the Right Method
올바른 방법 선택
| Method | Advantages | Suitable Situations |
|---|---|---|
| Regular for loop | Allows index control | Processing that requires element numbers |
| Enhanced for loop | Simple and easy to read syntax | Simple iteration processing |
| Stream API | Strong for conditional and chained processing | When combining filtering, mapping, and reduction |
5. Differences and Usage of ArrayList and LinkedList
5. ArrayList와 LinkedList의 차이점 및 사용법
The representative classes that implement Java’s List interface are ArrayList and LinkedList. Both can be used as List in the same way, but they have differences in internal structure and performance characteristics, so it is important to use them appropriately in the right situations.
Java의 List 인터페이스를 구현하는 대표적인 클래스는 ArrayList와 LinkedList입니다. 두 클래스 모두 List로 동일하게 사용할 수 있지만, 내부 구조와 성능 특성에 차이가 있어 상황에 맞게 적절히 사용하는 것이 중요합니다.
Characteristics and Suitable Use Cases of ArrayList
ArrayList의 특성 및 적합한 사용 사례
ArrayList internally uses a dynamic array (resizable array).
ArrayList는 내부적으로 동적 배열(크기 조절 가능한 배열)을 사용합니다.
Main Characteristics:
주요 특성:
- 랜덤 액세스(인덱스 기반)가 매우 빠름
- 리스트 끝에 요소 추가가 빠름 (평균 O(1))
- 중간에서의 삽입과 삭제가 느림 (O(n))
적합한 상황:
- 검색(
get())이 빈번한 상황 - 요소의 수가 미리 어느 정도 예측 가능한 상황
- 요소 추가/삭제가 최소화되고 읽기에 초점을 맞춘 처리
List<String> list = new ArrayList<>();
LinkedList의 특성과 적합한 사용 사례
LinkedList는 이중 연결 리스트 구조로 구현됩니다.
주요 특성:
- 요소 추가와 삭제가 빠름 (특히 시작이나 끝에서)
- 랜덤 액세스(
get(index))가 느림 (O(n)) - 메모리 소비가 ArrayList보다 약간 높음
적합한 상황:
- 요소가 자주 삽입되거나 삭제되는 상황 (특히 시작이나 중간에서)
- Queue나 Stack처럼 사용하고 싶을 때
- 반복에 초점을 맞추고 인덱스 액세스가 필요 없을 때
List<String> list = new LinkedList<>();
성능 비교
다음 표는 자주 사용되는 작업에 대한 이론적 시간 복잡도(Big O 표기법)를 보여줍니다.
| Operation | ArrayList | LinkedList |
|---|---|---|
get(int index) | O(1) | O(n) |
add(E e) (at the end) | O(1) | O(1) |
add(int index, E e) | O(n) | O(n) |
remove(int index) | O(n) | O(n) |
| Iteration | O(n) | O(n) |
* 실제 처리 시간은 데이터 크기, JVM 최적화 등에 의해 영향을 받을 수도 있습니다.

실무 사용 시 구분 포인트
- 데이터를 리스트로 취급하고 인덱스로 액세스할 때는 ArrayList 사용
- 시작이나 중간에서의 삽입/삭제가 빈번할 때는 LinkedList 사용
- 성능에 민감한 처리의 경우, 항상 벤치마크하고 검증하세요
6. List의 고급 사용법
여기서는 Java의 List를 더욱 편리하게 사용하는 고급 기법을 소개하겠습니다. List는 단순한 데이터 컬렉션이뿐만 아니라 정렬, 셔플링, 필터링, 변환 등을 통해 다양한 작업을 수행할 수 있습니다.
List 정렬 (Collections.sort)
Collections.sort()를 사용하면 List의 요소를 오름차순으로 정렬할 수 있습니다. 요소는 Comparable 인터페이스를 구현해야 합니다.
import java.util.*;
List<String> fruits = new ArrayList<>();
fruits.add("banana");
fruits.add("apple");
fruits.add("orange");
Collections.sort(fruits);
System.out.println(fruits); // [apple, banana, orange]
사용자 지정 순서로 정렬 (Comparator 사용)
fruits.sort(Comparator.reverseOrder()); // Sorts in descending order
List 셔플링 (Collections.shuffle)
요소를 무작위로 재배치하려면 Collections.shuffle()를 사용할 수 있습니다.
Collections.shuffle(fruits);
System.out.println(fruits); // [banana, orange, apple] (example)
게임의 카드 덱이나 무작위 표시 순서를 원할 때 유용합니다.
Stream API를 사용한 필터링 (filter)
Java 8부터의 Stream을 사용하면 조건에 맞는 요소만 추출하는 코드를 간결하게 작성할 수 있습니다.
List<String> filtered = fruits.stream()
.filter(fruit -> fruit.contains("a"))
.collect(Collectors.toList());
System.out.println(filtered); // [apple, banana, orange] (depending on original content and filter)
Stream API를 사용한 변환 (map)
요소를 다른 형식으로 변환하려면 map()을 사용하세요.
List<Integer> lengths = fruits.stream()
.map(String::length)
.collect(Collectors.toList());
System.out.println(lengths); // Lengths of each fruit name [5, 6, 6] etc.
map()은 데이터 형식 변환 및 전처리를 위한 강력한 도구입니다.
고급 작업 요약
| Operation | Usage Example | Main Use Cases |
|---|---|---|
| Sort | Collections.sort(list) | Sort in ascending order |
| Shuffle | Collections.shuffle(list) | Randomize the order of elements |
| Filter | stream().filter(...).collect() | Extract only elements that match a condition |
| Transform | stream().map(...).collect() | Transform the type or value of elements |
7. 일반적인 오류와 해결 방법
Java에서 List를 다룰 때, 초보자들이 자주 걸려넘어지는 것 중 하나는 “예외(오류)”입니다. 여기서는 자주 발생하는 대표적인 오류, 그 원인, 그리고 해결 방법을 구체적으로 설명하겠습니다.
IndexOutOfBoundsException
원인:
존재하지 않는 인덱스에 액세스하려 할 때 발생합니다.
answer.“`
List
System.out.println(list.get(1)); // Error: Index 1 out of bounds
#### 해결책:
인덱스가 유효하도록 접근하기 전에 크기를 확인하거나 조건 분기를 사용해 접근을 제어하세요.
if (list.size() > 1) { System.out.println(list.get(1)); }
### NullPointerException
#### 원인:
`null`인 List 또는 List 요소에 메서드를 호출할 때 발생합니다.
List
#### 해결책:
변수가 `null`이 아닌지 미리 확인하거나 Optional 등을 활용하세요.
if (list != null) { list.add(“apple”); }
또한 초기화를 잊지 않도록 주의하세요:
List
### ConcurrentModificationException
#### 원인:
`for-each` 루프나 `Iterator`를 사용해 순회하는 동안 List를 직접 수정하면 발생합니다.
for (String fruit : list) { if (fruit.equals(“banana”)) { list.remove(fruit); // ConcurrentModificationException } }
#### 해결책:
`Iterator`를 사용해 요소를 안전하게 제거하거나 `removeIf()`와 같은 메서드를 사용하세요.
Iterator
또는 Java 8 이후부터는 더 간결하게 다음과 같이 사용할 수 있습니다:
list.removeIf(fruit -> fruit.equals(“banana”));
### 기타 주의 사항
* **List가 null이 아닌지 확인하기**
* 변수를 선언만 하고 사용하지 않는 경우가 흔합니다. 초기화가 필수입니다.
* **인덱스가 0부터 시작한다는 이해**
* 초보자들은 종종 "첫 번째 요소가 인덱스 1"이라고 오해합니다.
### 오류 대처 요약
Error Name Primary Cause Example Solutions IndexOutOfBoundsException Accessing a non-existent index Check length with size() NullPointerException List or element is null Don't forget initialization, perform null checks ConcurrentModificationException Directly modifying the List during iteration Operate with Iterator or utilize removeIf()
## 8. 결론
### Java List 기본 복습
이 글에서는 Java List의 기본부터 고급까지 단계별로 설명했습니다. List는 Java 컬렉션 중 특히 자주 사용되며 **데이터를 유연하게 다루는 중요한 도구**입니다.
먼저 List가 무엇인지 이해한 뒤, 다음과 같은 점들을 배웠습니다:
* List는 **중복을 허용하는 순서가 있는 컬렉션**이며 인덱스 연산을 지원합니다.
* **ArrayList와 LinkedList**와 같은 대표적인 구현 클래스가 있으며, 각각 특성과 사용 사례가 다릅니다.
* 기본 연산(add, get, update, remove, search)을 숙달하면 데이터를 유연하게 조작할 수 있습니다.
* 상황에 맞는 **반복 처리**(for 루프, 향상된 for 루프, Stream API 등)를 활용합니다.
* 정렬, 필터링, 변환과 같은 고급 연산을 지원합니다.
* **일반적인 오류와 그 원인 및 해결책을 이해하면 문제를 예방**할 수 있습니다.
### ArrayList와 LinkedList 사용 구분
어떤 List 구현을 사용할지는 중요하며 **처리 내용과 데이터 양**에 따라 결정해야 합니다. 다음 기준이 가이드가 될 수 있습니다:
* **ArrayList** : 무작위 접근이 빈번하고 주로 읽기 작업
* **LinkedList** : 삽입/삭제가 빈번하고 접근 순서가 중요
### 앞으로의 학습 방향
List는 Java 컬렉션의 **입구**에 불과합니다. 보다 고급 데이터 구조와 유틸리티를 다루려면 다음 클래스와 기능에 대한 이해를 심화하는 것이 좋습니다:
* **Set과 Map** : 고유 요소 관리 및 키-값 쌍 구조
* **Collections 유틸리티 클래스** : 정렬, 최소/최대값 찾기 등
* **Stream API 활용** : 함수형 프로그래밍 도입
* **제네릭 이해** : 타입 안전한 컬렉션 연산
List 기본을 마스터하면 **전체 Java 프로그래밍을 훨씬 더 쉽게 관리**할 수 있습니다.
## 자주 묻는 질문 (FAQ)
Java List와 관련해 초보자들이 자주 궁금해하는 점들을 정리했습니다. 실무에서 흔히 마주치는 내용을 선정했습니다.
### Q1. Java의 List와 Array의 차이점은 무엇인가요?
**A.** 배열은 요소의 수가 고정되어 있으며, 선언 시 크기를 결정해야 합니다. 반면 List는 가변 크기를 가지며, 요소의 유연한 추가와 삭제가 가능합니다. 게다가 List는 많은 편리한 메서드(`add`, `remove`, `contains` 등)를 제공하며, 가독성과 유지보수성 측면에서 우수합니다.
### Q2. ArrayList와 LinkedList 중 어떤 것을 사용해야 할까요?
**A.** `ArrayList`는 주로 **랜덤 액세스(인덱스에 의한 검색)**가 빈번할 때 적합합니다. `LinkedList`는 **요소 삽입과 삭제가 빈번할 때** 적합합니다. 확신이 없을 때는 일반적으로 `ArrayList`부터 시작하는 것이 권장됩니다.
### Q3. List에 기본 타입(예: int나 double)을 저장할 수 있나요?
**A.** 직접적으로는 불가능합니다. Java의 List는 객체만 처리하므로, `int` 같은 기본 타입의 경우 해당 래퍼 클래스(`Integer`, `Double` 등)를 사용해야 합니다.
List
### Q4. List의 요소를 어떻게 정렬할 수 있나요?
**A.** `Collections.sort(list)`를 사용하여 오름차순으로 정렬할 수 있습니다. 또한, 사용자 정의 순서로 정렬하고 싶다면 `Comparator`를 지정하여 유연한 정렬이 가능합니다.
### Q5. 중복되지 않는 요소를 관리하려면 어떻게 해야 하나요?
**A.** List는 중복을 허용하는 컬렉션입니다. 중복을 피하고 싶다면 `Set`(예: `HashSet`)을 고려하세요. 다만 순서가 보장되지 않습니다. List를 유지하면서 중복을 제거하려면 다음 Stream 처리도 가능합니다:
List
### Q6. List에서 모든 요소를 지우려면 어떻게 하나요?
**A.** `clear()` 메서드를 사용하여 List에서 모든 요소를 제거할 수 있습니다.
list.clear(); “`
Q7. List에서 가장 자주 사용되는 연산은 무엇인가요?
A. 실제로 가장 자주 사용되는 연산은 add(추가), get(검색), remove(삭제), size(크기 확인)입니다. 이들을 익히면 대부분의 기본 처리를 커버할 수 있습니다.

