본문 바로가기

자바(Java)

Java Collection - 2

반응형

1. 자주 사용하는 자료구조 List, Map, Set 비교 요약 (Java Collection - 1 복습)


1) List: 요소의 순서가 중요하고, 중복을 허용해야 한다면 List

  • 순서가 있는 데이터의 컬렉션이다.
  • 중복된 요소를 포함할 수 있다.
  • 인덱스를 사용하여 요소에 접근할 수 있다.
  • 일반적으로 배열 형태로 구현된다.
  • Java에서는 ArrayList, LinkedList 등이 List 인터페이스를 구현하는 클래스이다.

2) Map: 키-값 쌍을 저장하고, 키를 기반으로 값을 검색해야 한다면 Map

  • 키-값(key-value) 쌍의 데이터를 저장하는 컬렉션이다.
  • 순서가 정의되어 있지 않다.
  • 키는 중복될 수 없지만, 값은 중복될 수 있다.
  • 키를 사용하여 값을 검색하고, 변경할 수 있다.
  • Java에서는 HashMap, LinkedHashMap, TreeMap 등이 Map 인터페이스를 구현하는 클래스이며, 일반적으로 HashMap 형태로 구현한다.

3) Set: 중복되지 않는 요소들의 집합을 다루고, 순서가 중요하지 않다면 Set

  • 중복되지 않는 요소들의 컬렉션이다.
  • 순서가 정의되어 있지 않다.
  • 요소 간의 관계는 순서가 아닌 동등성(equality)에 의해 결정된다.
  • 값을 검색하거나 변경하기 위해 인덱스를 사용할 수 없다.
  • Java에서는 HashSet, LinkedHashSet, TreeSet 등이 Set 인터페이스를 구현하는 클래스이며, 일반적으로 HashSet 형태로 구현된다.

2. 자주 사용하는 데이터 구조 세부 파악 (ArrayList, HashMap, HashSet)


1) ArrayList

  • ArrayList는 동적 배열로 구현되어 있으며, 크기를 동적으로 조정할 수 있다.
  • 요소들을 인덱스를 통해 접근할 수 있고, 순서가 유지된다.
  • 중복된 요소를 허용한다.
  • 요소를 추가하거나 삭제하는 작업이 빈번한 경우에 적합하다.
ArrayList<String> list = new ArrayList<>();
list.add("사과");
list.add("바나나");
list.add("딸기");

// 리스트 전체 출력: 기존의 for-each 문 사용
for (String fruit : list) {
    System.out.println(fruit);
}
// 람다식 적용
list.forEach(fruit -> System.out.println(fruit));

// 사과 개수 확인
long appleCount = list.stream().filter(fruit -> fruit.equals("사과")).count();
System.out.println("사과 개수: " + appleCount);

// 사과 존재 여부 확인
boolean isAppleExist = list.stream().anyMatch(fruit -> fruit.equals("사과"));
System.out.println("사과 존재 여부: " + isAppleExist);

2) HashMap

  • HashMap은 키-값 쌍으로 데이터를 저장하는 해시 테이블 기반의 구조이다.
  • 키는 중복되지 않으며, 값은 중복될 수 있다.
  • 해시 함수를 사용하여 데이터에 접근하므로 매우 빠른 검색 속도를 제공한다.
  • 데이터를 효율적으로 검색하고자 할 때 적합하다.
HashMap<String, Integer> map = new HashMap<>();
map.put("사과", 10);
map.put("바나나", 5);
map.put("딸기", 3);

// 리스트 전체 출력
map.forEach((fruit, quantity) -> System.out.println(fruit + ": " + quantity));

// 사과 개수 확인
int count = map.getOrDefault("사과", 0);
System.out.println("사과 개수: " + count);

// 사과 존재 여부 확인
boolean isAppleExist = map.containsKey("사과");
System.out.println("사과 존재 여부: " + isAppleExist);

3) HashSet

  • HashSet은 중복된 요소를 허용하지 않는 데이터 구조이다.
  • 해시 테이블을 사용하여 요소를 저장하므로 중복된 요소를 효율적으로 제거한다.
  • 요소의 순서를 보장하지 않는다.
  • 요소의 존재 여부를 빠르게 확인하고자 할 때 적합하다.
HashSet<String> set = new HashSet<>();
set.add("사과");
set.add("바나나");
set.add("딸기");

// 리스트 전체 출력
set.forEach(fruit -> System.out.println(fruit));

// 사과의 존재 여부 확인
boolean isAppleExist = set.contains("사과");
if (isAppleExist) {
    System.out.println("사과가 존재합니다.");
}

// 사과 개수 확인
long appleCount = set.stream().filter(fruit -> fruit.equals("사과")).count();
System.out.println("사과 개수: " + appleCount);

3. 반복자 Iterator


1) 정의

반복자(Iterator)는 Java Collection Framework에서 컬렉션 내의 요소들을 순차적으로 탐색하는 데 사용되는 인터페이스이다. 반복자를 통해 컬렉션의 요소에 접근하고 수정할 수 있다.


2) 사용 방법

ArrayList<String> list = new ArrayList<>();
list.add("사과");
list.add("바나나");
list.add("딸기");

Iterator<String> iterator = list.iterator();
while (iterator.hasNext()) {
    String fruit = iterator.next();
		if(fruit.equals("바나나"){
				iterator.remove();
		}
    System.out.println(fruit);
}
  • Iterator 인터페이스는 java.util 패키지에 정의되어 있다.
  • Iterator 객체는 컬렉션의 첫 번째 요소 앞에 위치하고, next() 메서드를 호출하여 요소를 차례로 반환한다.
  • hasNext() 메서드는 다음 요소의 존재 여부를 확인하며, 요소가 있는 경우 true를 반환한다.
  • remove() 메서드를 사용하여 현재 요소를 삭제할 수 있다.

3) 반복자를 사용한 데이터 참조 vs foreach문을 통한 데이터 직접 참조

Java Collection Framework의 데이터를 참조할 때 실제로는 반복자와 foreach 루프를 모두 사용할 수 있다.

대부분의 상황에서는 foreach 루프를 사용하여 직접 데이터를 참조하는 것이 더 편리하고 가독성이 좋다. foreach 루프는 반복자를 사용하는 코드보다 간결하며, 개발자가 직접 반복자를 다루는 부분을 신경쓰지 않아도 되기 때문이다.

종종 데이터를 삭제하거나 변경해야 하는 경우에는 반복자를 사용하는 것이 유용할 수 있다. 반복자는 컬렉션의 요소를 안전하게 삭제할 수 있도록 지원하며, 일부 컬렉션(ArrayList, LinkedList 등 순차적 데이터 구조)에서는 수정 작업에 반복자를 사용하는 것이 권장된다.

따라서 대부분의 경우에는 foreach 루프를 사용하여 데이터를 참조하고, 데이터를 삭제하거나 변경해야 하는 경우에는 반복자를 사용하는 것이 일반적이다.

 

4. 컬렉션을 이용한 정렬 및 찾기


1) 기초지식: Comparator<T> Interface

Comparator<T> 인터페이스Comparator<T>는 두 개의 객체를 비교하는 데 사용되는 인터페이스이다. Comparator<T>를 구현하여 사용자 지정 비교 로직을 구현하고, 이를 정렬 알고리즘 등에 전달하여 객체의 순서를 기준으로 작업을 수행할 수 있다. 즉, 정렬이나 정렬 기준을 지정하는 데 사용된다.


*Comparator<T> 인터페이스 원형

public interface Comparator<T> {
    int compare(T o1, T o2);
    // ...
}

compare 메서드는 두 개의 객체를 비교하여 순서를 결정한다. 이 메서드는 아래와 같은 반환 값의 의미를 갖는다.

  • 음수 값: o1은 o2보다 작다.
  • 0: o1과 o2는 같다.
  • 양수 값: o1은 o2보다 크다.

2) 정렬(Sorting)

자바 프레임워크에서 제공하는 정렬 기능은 주로 Collections 클래스와 Arrays 클래스에서 찾을 수 있다.


(1) Collections 클래스

- Collections.sort(List<T> list)

  • 이 메서드는 주어진 리스트를 기본적으로 오름차순으로 정렬한다.
  • 리스트의 요소는 Comparable 인터페이스를 구현한 객체들이어야 한다. 이 인터페이스를 구현한 객체들은 자연적인 순서를 갖고 있어 정렬이 가능하다.
  • 정렬은 리스트 내의 객체들을 변경하며, 반환값은 void이다.

- Collections.sort(List<T> list, Comparator<? super T> c)

  • 이 메서드는 주어진 리스트를 주어진 Comparator를 사용하여 정렬한다.
  • Comparator 객체 c는 T 타입의 객체들을 비교하는 로직을 담은 객체이다.
  • Comparator를 통해 비교 로직을 커스터마이징할 수 있기 때문에 객체의 자연적인 순서와 다른 기준으로 정렬할 수 있다.
  • 정렬은 리스트 내의 객체들을 변경하며, 반환값은 void이다.

(2) Arrays 클래스

- Arrays.sort(T[] arr)

  • 이 메서드는 주어진 배열을 기본적으로 오름차순으로 정렬한다.
  • 배열의 요소는 Comparable 인터페이스를 구현한 객체들이어야 한다.
  • 정렬은 배열 내의 요소들을 변경한다.

- Arrays.sort(T[] arr, Comparator<? super T> c)

  • 이 메서드는 주어진 배열을 주어진 Comparator를 사용하여 정렬한다.
  • Comparator 객체 c는 T 타입의 객체들을 비교하는 로직을 담은 객체이다.
  • 정렬은 배열 내의 요소들을 변경한다.

3) 찾기(Searching)

자바 프레임워크에서 제공하는 찾기 기능은 주로 Collections 클래스와 Arrays 클래스에서 찾을 수 있다.


(1) Collections 클래스

- Collections.binarySearch(List<? extends T> list, T key)

  • 이 메서드는 주어진 리스트에서 이진 검색을 사용하여 특정 요소를 찾는다.
  • 리스트는 이미 정렬되어 있어야 한다.
  • T는 검색할 객체들의 타입이다.
  • key는 찾고자 하는 요소이다.
  • 반환값은 찾은 요소의 인덱스이다. 찾지 못한 경우에는 -(삽입 포인트 + 1)의 값을 반환한다.

- Collections.binarySearch(List<? extends T> list, T key, Comparator<? super T> c)

  • 이 메서드는 주어진 리스트에서 이진 검색을 사용하여 특정 요소를 찾는다.
  • 리스트는 이미 정렬되어 있어야 한다.
  • T는 검색할 객체들의 타입이다.
  • key는 찾고자 하는 요소이다.
  • c는 T 타입의 객체들을 비교하는 로직을 담은 Comparator 객체이다.
  • 반환값은 찾은 요소의 인덱스이다. 찾지 못한 경우에는 -(삽입 포인트 + 1)의 값을 반환한다.

(2) Arrays 클래스

- Arrays.binarySearch(T[] arr, T key)

  • 이 메서드는 주어진 배열에서 이진 검색을 사용하여 특정 요소를 찾는다.
  • 배열은 이미 정렬되어 있어야 한다.
  • T는 검색할 객체들의 타입이다.
  • key는 찾고자 하는 요소이다.
  • 반환값은 찾은 요소의 인덱스이다. 찾지 못한 경우에는 -(삽입 포인트 + 1)의 값을 반환한다.

- Arrays.binarySearch(T[] arr, T key, Comparator<? super T> c)

  • 이 메서드는 주어진 배열에서 이진 검색을 사용하여 특정 요소를 찾는다.
  • 배열은 이미 정렬되어 있어야 합니다.
  • T는 검색할 객체들의 타입입니다.
  • key는 찾고자 하는 요소이다.
  • c는 T 타입의 객체들을 비교하는 로직을 담은 Comparator 객체입니다.
  • 반환값은 찾은 요소의 인덱스이다. 찾지 못한 경우에는 -(삽입 포인트 + 1)의 값을 반환한다.

4) sort(), binarySearch() 메소드 세부 분석

 

(1) sort() 메소드

public static <T> void sort(List<T> list, Comparator<? super T> c)
  • Comparator<? super T> c에서 <? super T>는 T 타입이거나 T의 상위 타입을 나타낸다. 이것은 Comparator 객체 c가 T 타입 또는 T를 상속하거나 구현한 타입들과 비교할 수 있음을 의미한다. 따라서, sort 메서드는 T 타입의 객체들을 정렬하는 데 사용되며, Comparator 객체는 T 타입 또는 T의 상위 타입과 비교할 수 있는 로직을 담고 있어야 한다.
  • 이 메서드는 주어진 리스트를 주어진 Comparator를 사용하여 정렬한다.
  • Comparator를 통해 비교 로직을 커스터마이징할 수 있기 때문에 객체의 자연적인 순서와 다른 기준으로 정렬할 수 있다.
  • 정렬은 리스트 내의 객체들을 변경하며, 반환값은 void이다.

(2) binarySearch() 메소드

public static <T> int binarySearch(List<? extends T> list, T key, Comparator<? super T> c)
  • List<? extends T> list에서 <? extends T>는 T 타입 또는 T의 하위 타입들을 나타낸다. 이것은 list에 T 타입 또는 T를 상속한 타입의 객체들을 저장할 수 있음을 의미한다. T 타입 또는 T의 하위 타입들과 key를 비교하고자 할 때, Comparator 객체 c는 T 타입 또는 T의 상위 타입과 비교할 수 있는 로직을 담고 있어야 한다. 그리고, 반환값은 찾은 요소의 인덱스이며, list에 저장된 객체들은 T 타입 또는 T의 하위 타입들이어야 한다.
  • list는 이미 정렬되어 있어야 하며, 해당 메서드는 주어진 리스트에서 이진 검색을 사용하여 특정 요소를 찾는다.
  • Comparator 를 통해 객체들을 비교하는 방식을 커스터마이징할 수 있다.
  • 반환값은 찾은 요소의 인덱스이다. 찾지 못한 경우에는 -(삽입 포인트 + 1)의 값을 반환한다. 삽입 포인트는 해당 요소를 삽입할 때 리스트의 정렬 순서를 유지할 수 있는 위치이다.
반응형

'자바(Java)' 카테고리의 다른 글

Java - 메소드 참조와 Optional 클래스  (0) 2023.08.11
Java - 람다식  (0) 2023.08.11
Java Collection - 1  (0) 2023.07.19
Java Generic  (0) 2023.07.03
Java 싱글톤 패턴(SingleTon Pattern) / 게터&세터(Getter & Setter)  (0) 2023.03.03