It's going to be one day 🍀

안녕하세요! 매일 매일 공부하려고 노력하는 백엔드 개발자 지망생의 공부 흔적입니다.

Back-End/Java # 교육

[Java 교육] Collection/List/Set/Map

2jin2 2024. 2. 15. 16:18

[공부 내용 정리]

컬렉션(Collection) : 요소를 수집해서 저장하는 것

ex) 다수개의 객체를 저장해 두고 필요할 때 마다 꺼내서 사용하는 경우

배열의 문제점을 해결하기 위해 java.util 패키지에 컬렉션과 관련된 인터페이스와 클래스들이 존재함. 이들을 총칭해서 컬렉션이라고 함. ex) List, Set, Map

List, Set 은 객체를 추가, 삭제하는 방법에 공통점이 있고 Collection 인터페이스로 정의해 두고 있음.(배열이나 트리 형태. 하나의 값만 저장함)

Map은 키(Key)와 값(Value)을 하나의 쌍으로 묶어서 관리하는 구조로 되어있음.


List Collection

List : 자료형의 개수가 계속 변하는 상황에서 유리한 자료구조 형태

List 컬렉션은 객체 자체를 저장하는게 아니라 객체의 번지를 참조함.

package chapter11.list;

import java.util.ArrayList;
import java.util.List;

public class ArrayListExample {
    public static void main(String[] args) {
        List<String> list = new ArrayList<>();
        // 요소 추가
        list.add("안");
        list.add("녕");
        list.add("하");
        list.add("세");
        list.add("요");

        // 요소 검색
        String element1 = list.get(0);
        boolean element2 = list.contains("안"); // boolean 리턴. 포함되어있으면 true, 아니면 false.
        String element3 = list.get(1);
        System.out.println(element1);
        System.out.println(element2);
        System.out.println(element3);

        // 객체 삭제
        System.out.println(list);
        list.remove(4);
        list.remove(3);
        list.remove(2);
        System.out.println(list);

        // null
        list.clear(); // 리스트 안에 있는 모든 요소들 삭제
        if (list.isEmpty() && list != null) { // NullPointException 피하기
            System.out.println("list가 비어있습니다.");
        }
    }
}

 

List 컬렉션에서 공통적으로 사용 가능한 List 인터페이스 메소드

ArrayList

List 인터페이스의 구현 클래스, ArrayList에 객체를 추가하게 되면 객체가 인덱스로 관리됨. 일반 배열과 ArrayList는 인덱스로 객체를 관리한다는 점에서 동일.

List<E> list = new ArrayList<E>();

  • ArrayList에 객체를 추가하면 인덱스 0부터 차례대로 저장됨. 만약 ArrayList에서 특정 인덱스의 객체를 제거하면 모두 앞으로 1씩 당겨짐.
  • 따라서 빈번한 객체 삭제와 삽입이 일어나는 곳에서는 ArrayList 사용이 바람직하지 않음.→ 이땐 LinkedList가 더 나음.
  • 인덱스 검색, 맨 마지막 객체 추가시엔 좋은 성능을 발휘함.

LinkedList

List 구현 클래스. LinkedList는 인접 참조를 링크해서 체인처럼 관리함.

List<E> list = new LinkedList<E>();

  • LinkedList에서 특정 인덱스의 객체를 제거하면 앞뒤 링크만 변경되고 나머지 링크는 변경되지 않음. 삽입시도 마찬가지
중간에 요소 추가 또는 삭제시엔 앞 뒤 링크만 변경하면 되는 LinkedList가 더 빠름. ArrayList는 뒤쪽 인덱스들을 모두 1씩 증가 또는 감소 시키는 시간이 필요하므로 처리 속도가 더 느림.

Set Collection

set 컬렉션은 저장 순서가 유지되지 않음. 또한 객체를 중복해서 저장할 수 없음.

 

HashSet

Set<E> set = new HashSet<E>();
  • HashSet은 객체들을 순서 없이 저장하고 동일한 객체는 중복 저장하지 않음.
  • HashSet은 객체를 저장하기 전에 먼저 객체의 hashCode() 메소드를 호출해서 해시코드를 얻어냄. 그리고 이미 저장되어있던 객체들의 해시코드와 비교함. 만약 동일한 해시코드가 있다면 equals() 메소드로 두 객체 비교 후 true가 나오면 동일한 객체로 판단하고 중복 저장하지 않음.

package chapter11.list;

import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;

public class HashSetExample {
    public static void main(String[] args) {
        // 객체 생성
        Set<String> stringSet = new HashSet<>();
        stringSet.add("요소1");
        stringSet.add("요소2");
        stringSet.add("요소3");
        stringSet.add("요소1");
        System.out.println(stringSet);

        // 객체 검색 (iterator 사용)
        Iterator<String> iterator = stringSet.iterator();
        while (iterator.hasNext()) {
            System.out.println(iterator.next());
        }
        System.out.println(stringSet.size());

        // 향상된 for문
        for (String str : stringSet) {
            System.out.println(str);
        }

        // 객체 삭제
        boolean element1 = stringSet.remove("요소2"); // remove의 리턴값은 bool. 삭제가 됐으면 true.
        System.out.println(element1);
        stringSet.clear(); // 내용 전부 삭제
        System.out.println(stringSet);
    }
}

Map Collection

Map 컬렉션은 키(key)와 값(value)으로 구성된 객체를 저장하는 구조임. 키는 중복될 수 없지만 값은 중복 저장될 수 있음.

Map 컬렉션에서 공통적으로 사용 가능한 Map 인터페이스 메소드

HashMap

Map 인터페이스를 구현한 대표적인 Map 컬렉션

Map<K, V> map = new HashMap<K, V>(); // K: 키 타입 파라미터, V: 값 타입 파라미터
package chapter11;

import java.util.HashMap;
import java.util.Map;
import java.util.Set;

public class MapExample {
    public static void main(String[] args) {
        HashMap<String, Integer> hashmap = new HashMap<>();
        // 객체 생성
        hashmap.put("key1" , 1);
        hashmap.put("key2" , 2);
        hashmap.put("key3" , 3);
        System.out.println("객체 생성 : "+hashmap);

        // 객체 찾기
        System.out.println("\\nget으로 값 뽑아내기 : "+hashmap.get("key1"));
        // getOrDefault() 메소드 사용
        System.out.println("getOrDefault() : "+hashmap.getOrDefault("key4", 4));

        boolean isContains = hashmap.containsKey("X");
        System.out.println("\\nisContains : " + isContains);
        boolean containsValue = hashmap.containsValue(3);
        System.out.println("containsValue : " + containsValue);

        // 객체를 하나씩 처리
        Set<String> keySet = hashmap.keySet();
        System.out.println("\\nkeySet : "+keySet);

        // 객체 삭제
        System.out.println("\\nremove 전 : "+hashmap);
        hashmap.remove("key2");
        System.out.println("remove 후 : "+hashmap);

        // Entry 사용 (key, value 쌍을 전체 순회할 수 있음. 따로 단독으로 뽑아낼 수 있음)
        Set<Map.Entry<String, Integer>> entrySet = hashmap.entrySet();
        for (Map.Entry<String, Integer> entry : entrySet) { // entry 에는 key, value 쌍 묶음이 들어있음
            String key = entry.getKey();
            Integer value = entry.getValue();
            System.out.println("\\nkey, value : "+key+", "+value);
            System.out.println("key만 : "+key);
        }

    }
}
  • get()과 getOrDefault()의 차이점 잘 알아두기

→ getOrDefault() : null 대신 기본 값을 반환하도록 함.

Hashtable

HashMap과 동일한 내부 구조를 가지고 있음.

하지만 Hashtable은 동기화된 (synchronized) 메소드로 구성되어있기 때문에 멀티 스레드가 동시에 이 메소드를 실행할 수 없고, 하나의 스레드가 실행을 완료해야 다른 스레드를 실행할 수 있음.

그래서 멀티 스레드 환경에서 안전하게 객체를 추가, 삭제할 수 있는 특징을 갖고있음. → thread safe 하다고 말함.

package chapter11;
import java.util.Hashtable;
import java.util.Map;
import java.util.Scanner;

public class HashTableExample {
    public static void main(String[] args) {
        Map<String, String> map = new Hashtable<>();
        map.put("spring", "qwer");
        map.put("sumer", "qwer1234");
        map.put("fall", "qwer123");
        map.put("winter", "qwe123");

        Scanner scanner = new Scanner(System.in);    // 키보드로 부터 입력된 내용을 받기 위해 생성

        while (true) {
            System.out.println("아이디와 비밀번호를 입력해주세요");
            System.out.println("아이디: ");
            String id = scanner.nextLine();        // 키보드로 입력한 아이디를 읽는다

            System.out.println("비밀번호: ");
            String password = scanner.nextLine();
            System.out.println();

            if (map.containsKey(id)) {
                if (map.get(id).equals(password)) {
                    System.out.println("로그인이 되었습니다");
                    break;
                } else {
                    System.out.println("비밀번호가 일치하지 않습니다!");
                }
            } else {
                System.out.println("입력하신 아이디가 존재하지 않습니다!\\n");
            }

            if (map.containsKey(id)){
                if (map.getOrDefault(id,"").equals(password)){
                    System.out.println("로그인이 되었습니다.");
                    break;
                } else {
                    System.out.println("비밀번호가 일치하지 않습니다.");
                }
            } else {
                System.out.println("아이디가 일치하지 않습니다.");
            }
        }
    }
}