[Java] 컬렉션 -3

최우형·2023년 3월 7일
1

Java

목록 보기
13/24
post-thumbnail

📌컬렉션 프레임워크

특정 자료 구조에 데이터를 추가하고, 삭제하고, 수정하고, 검색하는 등의 동작을 수행하는 편리한 메서드들을 제공

컬렉션 프레임워크의 주요 인터페이스로는 List, Set, Map을 제공한다.

List

  • List는 데이터의 순서가 유지되며, 중복 저장이 가능한 컬렉션을 구현
  • ArrayList, Vector, Stack, LinkedList 등이 List 인터페이스를 구현

Set

  • Set은 데이터의 순서가 유지되지 않으며, 중복 저장이 불가능한 컬렉션을 구현
  • HashSet, TreeSet 등이 Set 인터페이스를 구현

Map

  • Map은 키(key)와 값(value)의 쌍으로 데이터를 저장하는 컬렉션 구현
  • 데이터의 순서가 유지되지 않으며, 키는 값을 식별하기 위해 사용되므로 중복 저장이 불가능하지만, 값은 중복 저장이 가능
  • HashMap, HashTable, TreeMap, Properties 등

이 중 List와 Set은 공통점이 많아 위 그림과 같이 Colletion이라는 인터페이스로 묶인다.

이 둘의 공통점이 추출되어 추상화 된 것


List

List에서 공통적으로 사용 가능한 메서드

기능리턴 타입메서드설명
객체 추가voidadd(int index, Object element)주어진 인덱스에 객체를 추가
-booleanaddAll(int index, Collection c)주어진 인덱스에 컬렉션을 추가
-Objectset(int index, Object element)주어진 위치에 객체를 저장
객체 검색Objectget(int index)주어진 인덱스에 저장된 객체를 반환
-intindexOf(Object o) / lastIndexOf(Object o)순방향 / 역방향으로 탐색하여 주어진 객체의 위치를 반환
-ListIteratorlistIterator() / listIterator(int index)List의 객체를 탐색할 수 있는 ListIterator 반환 / 주어진 index부터 탐색할 수 있는 ListIterator 반환
-ListsubList(int fromIndex, int toIndex)fromIndex부터 toIndex에 있는 객체를 반환
객체 삭제Objectremove(int index)주어진 인덱스에 저장된 객체를 삭제하고 삭제된 객체를 반환
-booleanremove(Object o)주어진 객체를 삭제
객체 정렬voidsort(Comparator c)주어진 비교자(comparator)로 List를 정렬

ArrayList

ArrayList 는 List 인터페이스를 구현한 클래스다. ( 가장 많이 사용됨)
기존의 Vector를 개선한 것이므로, Vector보다는 주로 ArrayList를 사용한다.

객체를 추가하면 객체가 인덱스로 관리된다는 점에서 배열과 유사하다.

배열과 다르게 자동으로 저장 용량이 늘어난다.

리스트 계열 자료구조의 특성을 이어받아 데이터가 연속적으로 존재한다.

ArrayList<타입 매개변수> 객체명 = new ArrayList<타입 매개변수>(초기 저장 용량);

ArrayList<String> container1 = new ArrayList<String>();
// String 타입의 객체를 저장하는 ArrayList 생성
// 초기 용량이 인자로 전달되지 않으면 기본적으로 10으로 지정된다. 

ArrayList<String> container2 = new ArrayList<String>(30);
// String 타입의 객체를 저장하는 ArrayList 생성
// 초기 용량을 30으로 지정했다.

0부터 차례대로 저장된다.

특정 인덱스의 객체를 제거하면, 바로 뒤 인덱스부터 마지막 인덱스까지 모두 앞으로 1씩 당겨진다.

따라서 빈번한 객체 삭제와 삽입이 일어나는 곳에서는 LinkedList를 사용하는 것이 좋다.

ArrayList에서 String 객체를 추가, 검색, 삭제하는 예제

public class ArrayListExample {
	public static void main(String[] args) {

		// ArrayList를 생성하여 list에 할당
		ArrayList<String> list = new ArrayList<String>();

		// String 타입의 데이터를 ArrayList에 추가
		list.add("Java");
		list.add("egg");
		list.add("tree");

		// 저장된 총 객체 수 얻기
		int size = list.size(); 

		// 0번 인덱스의 객체 얻기
		String skill = list.get(0);

		// 저장된 총 객체 수 만큼 조회
		for(int i = 0; i < list.size(); i++){
			String str = list.get(i);
			System.out.println(i + ":" + str);
		}

		// for-each문으로 순회 
		for (String str: list) {
			System.out.println(str);
		}		

		// 0번 인덱스 객체 삭제
		list.remove(0);
	}
}

LinkedList

데이터를 효율적으로 추가, 삭제, 변경하기 위해 사용

public class LinkedListExample {
	public static void main(String[] args) {
		
		// Linked List를 생성하여 list에 할당
		LinkedList<String> list = new LinkedList<>();

		// String 타입의 데이터를 LinkedList에 추가
		list.add("Java");
		list.add("egg");
		list.add("tree");

		// 저장된 총 객체 수 얻기
		int size = list.size(); 

		// 0번 인덱스의 객체 얻기
		String skill = list.get(0);

		// 저장된 총 객체 수 만큼 조회
		for(int i = 0; i < list.size(); i++){
			String str = list.get(i);
			System.out.println(i + ":" + str);
		}

		// for-each문으로 순회
		for (String str: list) {
			System.out.println(str);
		}		

		// 0번 인덱스 객체 삭제
		list.remove(0);
	}
}

ArrayList와 LinkedList 차이

ArrayList 강점

  • 데이터를 순차적으로 추가하거나 삭제하는 경우
  • 데이터를 읽어들이는 경우

ArrayList 단점

  • 중간에 데이터를 추가하거나, 중간에 위치하는 데이터를 삭제하는 경우

LinkedList 강점

  • 중간에 데이터를 추가하거나 삭제하는 경우

LinkedList 단점

  • 검색이 느림

결론적으로 데이터의 잦은 변경이 예상된다면 LinkedList, 데이터의 개수가 변하지 않는다면 ArrayList를 사용하는 것이 좋다.


Iterator

컬렉션에 저장된 요소들을 순차적으로 읽어오는 역할

메서드설명
hasNext()읽어올 객체가 남아 있으면 true를 리턴하고, 없으면 false를 리턴합니다.
next()컬렉션에서 하나의 객체를 읽어옵니다. 이 때, next()를 호출하기 전에 hasNext()를 통해 읽어올 다음 요소가 있는지 먼저 확인해야 합니다.
remove()next()를 통해 읽어온 객체를 삭제합니다. next()를 호출한 다음에 remove()를 호출해야 합니다.

List에서 String 객체들을 반복해서 하나씩 가져오는 예제

ArrayList<String> list = ...;
Iterator<String> iterator = list.iterator();

while(iterator.hasNext()) {     // 읽어올 다음 객체가 있다면 
	String str = iterator.next(); // next()를 통해 다음 객체를 읽어옵니다. 
	...
}
ArrayList<String> list = ...;
Iterator<String> iterator = list.iterator();

while(iterator.hasNext()){        // 다음 객체가 있다면
	String str = iterator.next();   // 객체를 읽어오고,
	if(str.equals("str과 같은 단어")){ // 조건에 부합한다면
		iterator.remove();            // 해당 객체를 컬렉션에서 제거합니다. 
	}
}

Set

요소의 중복을 허용하지 않고, 저장 순서를 유지하지 않는 컬렉션

기능리턴 타입메서드설명
객체 추가booleanadd(Object O)주어진 객체를 추가하고, 성공하면 true를, 중복 객체면 false를 반환합니다.
객체 검색booleancontains(Object O)주어진 객체가 Set에 존재하는지 확인합니다.
-booleanisEmpty()Set이 비어있는지 확인합니다.
-IteratorIterator()저장된 객체를 하나씩 읽어오는 반복자를 리턴합니다.
-intsize()저장되어 있는 전체 객체의 수를 리턴합니다.
객체 삭제voidclear()Set에 저장되어져 있는 모든 객체를 삭제합니다.
-booleanremove(Object O)주어진 객체를 삭제합니다.

HashSet

중복된 값을 허용하지 않으며, 저장 순서를 유지하지 않는다.

import java.util.*;

public class Main {
    public static void main(String[] args) {

				// HashSet 생성
        HashSet<String > languages = new HashSet<String>();

				// HashSet에 객체 추가
        languages.add("Java"); 
        languages.add("Python");
        languages.add("Javascript");
        languages.add("C++");
        languages.add("Kotlin");
        languages.add("Ruby");
        languages.add("Java"); // 중복

				// 반복자 생성하여 it에 할당
        Iterator it = languages.iterator();

				// 반복자를 통해 HashSet을 순회하며 각 요소들을 출력
        while(it.hasNext()) {
            System.out.println(it.next());
        }
    }
}

TreeSet

이진 탐색 트리 형태로 데이터를 저장
데이터의 중복 저장을 허용하지 않고 저장 순서를 유지하지 않는 Set 인터페이스의 특징 그대로 유지

모든 왼쪽 자식의 값이 루트나 부모보다 작고, 모든 오른쪽 자식의 값이 루트나 부모보다는 큰 값을 가지는 특징

import java.util.TreeSet;

public class TreeSetExample {
    public static void main(String[] args) {

				// TreeSet 생성
        TreeSet<String> workers = new TreeSet<>();

				// TreeSet에 요소 추가
        workers.add("Lee Java");
        workers.add("Park Hacker");
        workers.add("Kim Coding");

        System.out.println(workers);
        System.out.println(workers.first());
        System.out.println(workers.last());
        System.out.println(workers.higher("Lee"));
        System.out.println(workers.subSet("Kim", "Park"));
    }
}
/// 오름 차순으로 나온다.

자동으로 사전 편찬 순에 따라 오름차순으로 정렬된다.


Map

키(Key)는 중복 저장될 수 없다.
값(Value)은 중복 저장이 가능하다.

그래서 주로 Key를 매개값으로 갖는 메서드가 많다.

기능리턴 타입메서드설명
객체 추가Objectput(Object key, Object value)주어진 키로 값을 저장합니다. 해당 키가 새로운 키일 경우 null을 리턴하지만, 동일한 키가 있을 경우에는 기존의 값을 대체하고 대체되기 이전의 값을 리턴합니다.
객체 검색booleancontainsKey(Object key)주어진 키가 있으면 true, 없으면 false를 리턴합니다.
-booleancontainsValue(Object value)주어진 값이 있으면 true, 없으면 false를 리턴합니다.
-SetentrySet()키와 값의 쌍으로 구성된 모든 Map.Entry 객체를 Set에 담아서 리턴합니다.
-Objectget(Object key)주어진 키에 해당하는 값을 리턴합니다.
-booleanisEmpty()컬렉션이 비어 있는지 확인합니다.
-SetkeySet()모든 키를 Set 객체에 담아서 리턴합니다.
-intsize()저장된 Entry 객체의 총 갯수를 리턴합니다.
-Collectionvalues()저장된 모든 값을 Collection에 담아서 리턴합니다.
객체 삭제voidclear()모든 Map.Entry(키와 값)을 삭제합니다.
-Objectremove(Object key)주어진 키와 일치하는 Map.Entry를 삭제하고 값을 리턴합니다.

HashMap

삽입되는 순서와 위치가 관계가 없다.
많은 양의 데이터를 검색하는 데 있어서 뛰어난 성능을 보인다.

리턴 타입메서드설명
booleanequals(Object O)동일한 Entry 객체인지 비교한다.
ObjectgetKey()Entry 객체의 Key 객체를 반환한다.
ObjectgetValue()Entry 객체의 Value 객체를 반환한다.
inthashCode()Entry 객체의 해시코드를 반환한다.
ObjectsetValue(Object value)Entry 객체의 Value 객체를 인자로 전달한 value 객체로 바꾼다.

생성하는 법

HashMap<String, Integer> hashmap = new HashMap<>();
//예제
import java.util.*;

public class HashMapExample {
    public static void main(String[] args) {

	    // HashMap 생성
        HashMap<String, Integer> map = new HashMap<>();

        // Entry 객체 저장
        map.put("피카츄", 85);
        map.put("꼬부기", 95);
        map.put("야도란", 75);
        map.put("파이리", 65);
        map.put("피존투", 15);

        // 저장된 총 Entry 수 얻기
        System.out.println("총 entry 수: " + map.size());

        // 객체 찾기
        System.out.println("파이리 : " + map.get("파이리"));
				
        // key를 요소로 가지는 Set을 생성 -> 아래에서 순회하기 위해 필요합니다. 
        Set<String> keySet = map.keySet();

        // keySet을 순회하면서 value를 읽어옵니다. 
        Iterator<String> keyIterator = keySet.iterator();
        while(keyIterator.hasNext()) {
            String key = keyIterator.next();
            Integer value = map.get(key);
            System.out.println(key + " : " + value);
        }

        // 객체 삭제
        map.remove("피존투");

        System.out.println("총 entry 수: " + map.size());

        // Entry 객체를 요소로 가지는 Set을 생성 -> 아래에서 순회하기 위해 필요합니다. 
        Set<Map.Entry<String, Integer>> entrySet = map.entrySet();

        // entrySet을 순회하면서 value를 읽어옵니다. 
        Iterator<Map.Entry<String, Integer>> entryIterator = entrySet.iterator();
        while(entryIterator.hasNext()) {
            Map.Entry<String, Integer> entry = entryIterator.next();
            String key = entry.getKey(); // Map.Entry 인터페이스의 메서드
            Integer value = entry.getValue(); // Map.Entry 인터페이스의 메서드
            System.out.println(key + " : " + value);
        }

        // 객체 전체 삭제
        map.clear();
    }
}

Map은 키와 값을 쌍으로 저장하기에 interator()를 직접 호출할 수 없다. 그 대신 keySet() 이나 entrySet()메서드를 이용해 Set 형태로 반환된 컬렉션에 iterator()를 호출하여 반복자를 만든 후, 반복자를 통해 순회할 수 있다.


Hashtable

HashMap이 Hashtable의 새로운 버전이다.

//로그인 예제
import java.util.*;

public class HashtableExample {
    public static void main(String[] args){

        Hashtable<String, String> map = new Hashtable<String, String>();

        map.put("Spring", "345");
        map.put("Summer", "678");
        map.put("Fall", "91011");
        map.put("Winter", "1212");

        System.out.println(map);

        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();

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

⭐정리!

어떤 컬렉션 클래스를 사용할지 모르겠다면?

profile
프로젝트, 오류, CS 공부, 코테 등을 꾸준히 기록하는 저만의 기술 블로그입니다!

0개의 댓글