개발 공부/Java | SpringBoot

[Java/ChatGPT] Day 14: 컬렉션 프레임워크 기초(List, Set, Map)

dev.jelee 2025. 6. 22. 20:24

[ 학습 목표 ]

  • 자바에서 데이터를 담는 대표적인 자료구조인 List, Set, Map을 이해하고 사용할 수 있다.
  • 각각의 특징, 선언 방법, 주요 메서드를 알아본다.

[ 이론 ]

1. 컬렉션 프레임워크란?

  • 자바에서 데이터(객체)를 효율적으로 저장하고 관리하기 위한 표준화된 자료구조 모음

 

2. 컬렉션 프레임워크 특징

  • 배열보다 유연하고 다양한 기능을 제공
  • 대표 인터페이스: List, Set, Map

 

3. List

  • 순서가 있고, 중복을 허용하는 자료구조
import java.util.ArrayList;
import java.util.List;

public class ListExample {
	public static void main(String[] args) {
		List<String> list = new ArrayList<>();
        
        list.add("사과");
        list.add("바나나);
        list.add("사과"); // 중복 가능
        
        for (String item : list) {
        	System.out.println(item);
        }
    }
}

 

4. List 주요 메서드

메서드 설명
add() 요소 추가
get(index) 요소 조회
remove(index) 요소 제거
size() 요소 개수

 

5. Set

  • 순서가 없고, 중복을 허용하지 않음
import java.util.HashSet;
import java.util.Set;

public class SetExample {
	public static void main(String[] args) {
    	Set<String> set = new HashSet<>();
        
        set.add("사과");
        set.add("바나나");
        set.add("사과"); // 중복 무시됨
        
        for (String item : set) {
        	System.out.println(item);
        }
    }
}

 

6. Map

  • key와 value를 쌍으로 저장 (ex. 주민번호 -> 이름)
import java.util.HashMap;
import java.util.Map;

public class MapExample {
	public static void main(String[] args) {
    	Map<String, String> map = new HashMap<>();
        
        map.put("apple", "사과);
        map.put("banana", "바나나);
        map.put("apple", "애플"); // 같은 키는 덮어씀
        
        System.out.println(map.get("apple")) // "애플" 출력
    }
}

 

7. Map 주요 메서드

메서드 설명
put(key, value) 추가/수정
get(key) 값 조회
remove(key) 키 제거
keSet() 모든 키 반환
values() 모든 값 반환

 

8. 자료구조 정리표

컬렉션 순서 중복 키-값 구조
List O O X
Set X X X
Map X X(키) O (key-value)

[ 실습 ]

1. List 실습

  • List<String>에 음식 5개를 추가하고 전체 출력하기

2. Set 실습

  • Set<Integer>에 중복된 숫자를 포함해 6개 추가하고 전체 출력 (중복 제거 확인)

3. Map 실습

  • Map<String, String>에 영어 단어 3개를 key로 넣고, 한글 뜻을 value로 넣고 출력하기
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

public class Main {
  public static void main(String[] args) {
    List<String> food = new ArrayList<>();
    Set<Integer> num = new HashSet<>();
    Map<String, String> engWord = new HashMap<>();

    // List 실습: 음식 5개 추가 + 출력
    food.add("된장찌개");
    food.add("김치찌개");
    food.add("불고기");
    food.add("비빔밥");
    food.add("볶음밥");

    for (String item : food) {
      System.out.print(item + " ");
    }
    System.out.println();

    // Set 실습: 중복된 숫자 포함해 6개 추가 + 출력
    num.add(1);
    num.add(2);
    num.add(3);
    num.add(5);
    num.add(7);
    num.add(1);

    for (Integer item : num) {
      System.out.print(item + " ");
    }
    System.out.println();

    // Map 실습: 3개 단어를 key로 넣고, 한글 뜻은 value로 넣기 + 출력
    engWord.put("apple", "사과");
    engWord.put("banana", "바나나");
    engWord.put("orange", "오렌지");

    System.out.println(engWord.keySet());
    System.out.println(engWord.values());

    // Map 실습2: Map에서 전체 key-value를 직접 출력
    for (String key : engWord.keySet()) {
      System.out.println(key + " : " + engWord.get(key));
    }
  }
}

 

 


[ 메모 ]

  • ArrayList<String> list = new ArrayList<>(); 와 List<String> list = new ArrayList<>(); 차이점을 알아보니 선언 타입의 차이었다.
    • ArrayList<String> : 구체적인 클래스 타입
    • List<String> : 인터페이스 타입
  • 구체적인 클래스 타입으로 선언한 것과 인터페이스 타입으로 선언한 것은 의미가 달랐다.
    • ArrayList<String> list = new ArrayList<>(); : 구체적인 구현 클래스로 선언하고 사용하겠다는 의미
    • List<String> list = new ArrayList<>(); : 인터페이스 타입으로 선언하고 나중에 구현체는 바꿔도 된다는 유연성을 뜻함
  • 여기서 왜 인터페이스 타입으로 선언하는지를 알아보았다.
    • 유연성과 확장성: 나중에 ArrayList 말고 다른 List 구현체로 쉽게 바꿀 수 있기 때문에.
    • 객체지향 설계 원칙 중 하나인 "구현보다는 인터페이스에 의존하라"
    • 인터페이스 타입으로 선언하면 코드가 더 추상적이고 재사용 가능해지기 때문에.
    • 테스트 시 List를 흉내 내는 가짜 객체(mock)도 쉽게 넣을 수 있다.
  • ArrayList는 List와 ArrayList 전용 메서드까지 사요이 가능하지만 List는 그러하지 않다. 그렇기 때문에 만약에 List<> 타입으로 선언했다면 ArrayList<String> realList = (ArrayList<String>) list; 이렇게 형변환을 해서 ArrayList의 메서드를 사용할 수 있다.
  • 결론은 실무에서 대부분의 경우 List 인터페이스로 선언하고, 특정 기능이 필요할 때만 형변환하거나 별도 분리한다고 한다.
  • 만약에 ArrayList 전용 기능이 자주 필요하면 처음부터 ArrayList 타입으로 선언할 수도 있다.