[자료구조] 자바 Collection 총 정리(자료구조, Iterator, Iterable, Comparator, Comparable)

2025. 2. 28. 23:39·Java/Collection

 

컬렉션

#Abstract/Java


/Collection 인터페이스
/List 자료 구조
/ArrayList - 배열 리스트
/연결리스트 - LinkedList
/자바 List 인터페이스
/자바 ArrayList
/자바 LinkedList
/Set
/해시 알고리즘
/자바의 hashCode()
/자바 Set 인터페이스
/Map 인터페이스
/Stack - 사용 금지
/Queue 인터페이스
/Deque 인터페이스
/Deque와 Stack, Queue
/순회
/Iterable, Iterator
/자바가 제공하는 Iterable, Iterator
/정렬 - Comparable, Comparator
/컬렉션 유틸
/Collection 인터페이스 정리


Collection 인터페이스

Collection 인터페이스는 java.util 패키지의 컬렉션 프레임워크의 핵심 인터페이스 중 하나이다. 이 인터페이스는 자바에서 다양한 컬렉션, 즉 데이터 그룹을 다루기 위한 메서드를 정의한다. Collection 인터페이스는 List , Set , Queue 와 같은 다양한 하위 인터페이스와 함께 사용되며, 이를 통해 데이터를 리스트, 세트, 큐 등의 형태로 관 리할 수 있다. 자세한 내용은 뒤에서 다룬다.


List 자료 구조

정적인 배열의 크기로부터 발생하는 문제를 해결하기 등장한 자료구조


순서가 있고, 중복을 허용하는 자료 구조를 리스트라 한다.
일반적으로 배열과 리스트는 구분해서 이야기한다. 리스트는 배열보다 유연한 자료 구조로, 크기가 동적으로 변할 수 있다.

  • 배열: 순서가 있고 중복을 허용하지만 크기가 정적으로 고정된다.
  • 리스트: 순서가 있고 중복을 허용하지만 크기가 동적으로 변할 수 있다.

ArrayList - 배열 리스트

배열 리스트(ArrayList ): 리스트(List) 자료 구조를 사용하는데, 내부의 데이터는 배열(Array)에 보관하는 것이다.


배열 리스트의 빅오

  • 데이터 추가
    • 마지막에 추가: O(1)
    • 앞, 중간에 추가: O(n)
  • 데이터 삭제
    • 마지막에 삭제: O(1)
    • 앞, 중간에 삭제: O(n)
  • 인덱스 조회: O(1)
  • 데이터 검색: O(n)

배열 리스트는 언제 사용할까?

배열 리스트는 마지막에 데이터를 추가하거나 마지막에 있는 데이터를 삭제할 때는 O(1)로 매우 빠르지만, 중간에 데이
터를 추가하거나 삭제하는 경우에는 O(n)으로 느리다.


배열 리스트는 보통 데이터를 중간에 추가하고 삭제하는 변경 보다는, 데이터를 순서대로 입력하고(데이터를 마지막에추가하고), 순서대로 출력하는 경우에 가장 효율적이다.


또한 정확한 크기를 미리 알지 못하면 메모리가 낭비된다. 배열을 사용하므로 배열 뒷 부분에 사용되지 않고, 낭비되는 메모리가 있다


연결리스트 - LinkedList

배열리스트의 두 가지 단점을 해결하기 위해 등장한 자료구조

  1. 배열의 사용하지 않는 공간 낭비: 데이터가 얼마나 추가될지 예측할 수 없는 경우 나머지는 공간은 사용되지 않고 낭비된다.
  2. 배열의 중간에 데이터 추가/삭제: 많은 데이터를 이동해야 하기 때문에 성능이 좋지 않다. O(n)

노드

중간에 데이터를 추가하는 경우를 생각해보자. 배열로는 도저히 방법이 생각나지 않는다. 이 때 등장한 자료구조가 노드이다. 노드를 만들고 각 노드를 서로 연결하는 방식이다.


노드에는 item에 해당하는 필드, 그리고 다음 노드를 가리키는 필드 총 두 개가 존재한다.


  • 각각의 노드가 참조를 통해 연결(Link, 링크) 되어 있다.
  • 데이터를 추가할 때 동적으로 필요한 만큼의 노드만 만들어서 연결하면 된다. 따라서 배열과 다르게 메모리를 낭비하지 않는다
    • 물론 next 필드를 통해 참조값을 보관해야 하기 때문에 배열과 비교해서 추가적인 메모리 낭비도 발생한다.
  • 배열 리스트와 다르게 중간에 데이터를 추가하거나 삭제할 때 기존 데이터를 한 칸씩 이동씩 이동하지 않아도 된다.


배열 리스트 vs 연결 리스트 사용
데이터를 조회할 일이 많고, 뒷 부분에 데이터를 추가한다면 배열 리스트가 보통 더 좋은 성능을 제공한다. 앞쪽의 데이
터를 추가하거나 삭제할 일이 많다면 연결 리스트를 사용하는 것이 보통 더 좋은 성능을 제공한다.


대부분의 경우 배열 리스트가 성능상 유리하다. 이런 이유로 실무에서는 주로 배열 리스트를 기본으로 사용한다.
만약 데이터를 앞쪽에서 자주 추가하거나 삭제할 일이 있다면 연결 리스트를 고려하자.


이중 연결 리스트

마지막 노드에 바로 접근할 수 있다면, “뒤에 추가”의 시간 복잡도를 O(1)로 줄일 수 있다. 이중 연결리스트를 이용하면 이를 구현할 수 있다.


배열 리스트 vs 연결 리스트 시간 복잡도와 실제 성능

정리하면 이론적으로 MyLinkedList 가 평균 추가(중간 삽입)에 있어 더 효율적일 수 있지만, 현대 컴퓨터 시스템의 메모리 접근 패턴, CPU 캐시 최적화 등을 고려할 때 MyArrayList 가 실제 사용 환경에서 더 나은 성능을 보여주는 경우가 많다

  • 이론적으로 MyLinkedList 의 평균 추가(중간 삽입) 연산은 MyArrayList 보다 빠를 수 있다. 그러나 실제 성능은 요소의 순차적 접근 속도, 메모리 할당 및 해제 비용, CPU 캐시 활용도 등 다양한 요소에 의해 영향을 받는다.
  • MyArrayList 는 요소들이 메모리 상에서 연속적으로 위치하여 CPU 캐시 효율이 좋고, 메모리 접근 속도가 빠르다.
  • 반면, MyLinkedList 는 각 요소가 별도의 객체로 존재하고 다음 요소의 참조를 저장하기 때문에 CPU 캐시 효율이 떨어지고, 메모리 접근 속도가 상대적으로 느릴 수 있다
  • MyArrayList 의 경우 CAPACITY 를 넘어서면 배열을 다시 만들고 복사하는 과정이 추가된다. 하지만 한번에 2배씩 늘어나기 때문에 이 과정은 가끔 발생하므로, 전체 성능에 큰 영향을 주지는 않는다.

자바 List 인터페이스



List 인터페이스는 java.util 패키지에 있는 컬렉션 프레임워크의 일부다. List 는 객체들의 순서가 있는 컬렉션을 나타내며, 같은 객체의 중복 저장을 허용한다. 이 리스트는 배열과 비슷하지만, 크기가 동적으로 변화하는 컬렉션을 다룰 때 유연하게 사용할 수 있다.


List 인터페이스의 주요 메서드

메서드 설명
add(E e) 리스트의 끝에 지정된 요소를 추가한다.
add(int index, E element) 리스트의 지정된 위치에 요소를 삽입한다.
addAll(Collection<? extends E> c) 지정된 컬렉션의 모든 요소를 리스트의 끝에 추가한다.
addAll(int index, Collection<? extends E> c) 지정된 컬렉션의 모든 요소를 리스트의 지정된 위치에 추가한다.
get(int index) 리스트에서 지정된 위치의 요소를 반환한다.
set(int index, E element) 지정한 위치의 요소를 변경하고, 이전 요소를 반환한다.
remove(int index) 리스트에서 지정된 위치의 요소를 제거하고 그 요소를 반환한다.
remove(Object o) 리스트에서 지정된 첫 번째 요소를 제거한다.
clear() 리스트에서 모든 요소를 제거한다.
indexOf(Object o) 리스트에서 지정된 요소의 첫 번째 인덱스를 반환한다.
lastIndexOf(Object o) 리스트에서 지정된 요소의 마지막 인덱스를 반환한다.
contains(Object o) 리스트가 지정된 요소를 포함하고 있는지 여부를 반환한다.
sort(Comparator<? super E> c) 리스트의 요소를 지정된 비교자에 따라 정렬한다.
subList(int fromIndex, int toIndex) 리스트의 일부분의 뷰를 반환한다.
size() 리스트의 요소 수를 반환한다.
isEmpty() 리스트가 비어있는지 여부를 반환한다.
iterator() 리스트의 요소에 대한 반복자를 반환한다.
toArray() 리스트의 모든 요소를 배열로 반환한다.
toArray(T[] a) 리스트의 모든 요소를 지정된 배열로 반환한다.

자바 ArrayList

java.util.ArrayList

  • 배열을 사용해서 데이터를 관리한다.
  • 기본 CAPACITY 는 10이다.(DEFAULT_CAPACITY = 10 )
    • CAPACITY 를 넘어가면 배열을 50% 증가한다.
    • 10 15 22 33 49로 증가한다. (최적화는 자바 버전에 따라 달라질 수 있다.)
  • 메모리 고속 복사 연산을 사용한다.
    • ArrayList 의 중간 위치에 데이터를 추가하면, 추가할 위치 이후의 모든 요소를 한 칸씩 뒤로 이동시켜야 한다.
    • 자바가 제공하는 ArrayList 는 이 부분을 최적화 하는데, 배열의 요소 이동은 시스템 레벨에서 최적화된 메모리 고속 복사 연산을 사용해서 비교적 빠르게 수행된다. 참고로 System.arraycopy() 를 사용한다.

데이터 추가 - 메모리 고속 복사 연산 사용


시스템 레벨에서 배열을 한 번에 아주 빠르게 복사한다. 이 부분은 OS, 하드웨어에 따라 성능이 다르기 때문에 정
확한 측정이 어렵지만, 한 칸씩 이동하는 방식과 비교하면 보통 수 배 이상의 빠른 성능을 제공한다.


자바 LinkedList

java.util.LinkedList


자바의 LinkedList 특징

  • 이중 연결 리스트 구조
  • 첫 번째 노드와 마지막 노드 둘다 참조
  • 마지막 노드에 대한 참조를 제공한다. 따라서 데이터를 마지막에 추가하는 경우에도 O(1)의 성능을 제공한다.

성능 측정


직접 만든 배열 리스트와 연결 리스트 - 성능 비교 표

기능 배열 리스트 연결 리스트
앞에 추가(삭제) O(n) - 1369ms O(1) - 2ms
평균 추가(삭제) O(n) - 651ms O(n) - 1112ms
뒤에 추가(삭제) O(1) - 2ms O(n) - 2195ms
인덱스 조회 O(1) - 1ms O(n) - 평균 438ms
검색 O(n) - 평균 115ms O(n) - 평균 492ms

자바가 제공하는 배열 리스트와 연결 리스트 - 성능 비교 표

기능 배열 리스트 연결 리스트
앞에 추가(삭제) O(n) - 106ms O(1) - 2ms
평균 추가(삭제) O(n) - 49ms O(n) - 1116ms
뒤에 추가(삭제) O(1) - 1ms O(1) - 2ms
인덱스 조회 O(1) - 1ms O(n) - 평균 439ms
검색 O(n) - 평균 104ms O(n) - 평균 473ms

데이터를 추가할 때 자바 ArrayList가 직접 구현한 MyArrayList보다 빠른 이유

  • 자바의 배열 리스트는 이때 메모리 고속 복사를 사용하기 때문에 성능이 최적화된다
  • 메모리 고속 복사는 시스템에 따라 성능이 다르기 때문에 정확한 계산은 어렵지만 대략 O(n/10) 정도로 추정한다.

정리하면 이론적으로 LinkedList 가 중간 삽입에 있어 더 효율적일 수 있지만, 현대 컴퓨터 시스템의 메모리 접근 패턴, CPU 캐시 최적화, 메모리 고속 복사 등을 고려할 때 ArrayList 가 실제 사용 환경에서 더 나은 성능을 보여주는 경우가 많다.


Set

  • 세트(셋)는 유일한 요소들의 컬렉션
  • 특징
    • 중복된 요소가 존재하지 않음
    • 순서를 보장하지 않는다.
    • 빠른 검색: 요소의 유무를 빠르게 확인할 수 있도록 최적화되어 있다.
  • 용도: 중복을 허용하지 않고, 요소의 유무만 중요한 경우에 사용

메서드

  • add(value) : 셋에 중복된 값이 있는지 체크하고, 중복된 값이 있으면 false 를 반환한다. 중복된 값이 없으면 값을 저장하고 true 를 반환한다.
    • O(n)
  • contains(value) : 셋에 값이 있는지 확인한다. 값이 있으면 true 를 반환하고, 값이 없으면 false 를 반환한다.
    • O(n)

데이터 추가, 검색 모두 O(n)으로 성능이 좋지 않다.
이 부분을 개선하기 위해 해시(hash) 알고리즘이 등장했다.


해시 알고리즘

배열 기반 set에서 O(n)이던 검색 성능을, 해시 알고리즘을 통해 검색 성능을 평균 O(1)로 끌어올릴 수 있다.


  • O(1)? 인덱스를 통한 접근
  • 인덱스를 값이랑 매칭 시키면 되겠다.
  • 그런데 값의 범위가 너무 크면 MLE가 나는데?
  • 범위가 1~10억이라도 10억개의 요소를 모두 사용하지 않는다.
    • 값을 더 적은 범위의 인덱스로 매핑해보자.

이렇게 배열의 인덱스로 사용할 수 있도록 원래의 값을 계산한 인덱스를 해시 인덱스(hashIndex)라 한다.


해시 충돌

나머지 연산을 통해 해시 인덱스를 구하는 방식을 생각해보자. 이 방식에는 문제가 존재한다. 10으로 나눈 나머지가 같은 값들에서 충돌이 발생한다. 1과 11은 해시 인덱스 1에서 충돌이 발생한다.


해시 충돌 해결

나머지 연산의 경우 나누는 값을 키워주면 충돌이 줄어든다. 물론 나누는 값을 단순히 키운다고 해서 해시 충돌 문제를 완전히 해결할 수는 없다. 해시 인덱스를 구하는 알고리즘을 적당히 조절하면 해시 충돌 확률을 낮출 수 있다는 것은 알 수 있다.


다른 관점에서 살펴보면, 해시 충돌이 일어났을 때 단순하게 같은 해시 인덱스의 값을 같은 인덱스에 함께 저장해버림으로써 해결할 수도 있다. 이런 방식을 체이닝(chaining)이라고 한다.


최악의 경우
모든 데이터가 9로 나눠떨어진다고 해보자. (9, 19, 29, 39, ….) 이런 최악의 경우에는 O(n) 성능을 보인다.


해시 충돌 확률
해시 충돌은 가급적 발생하지 않도록 해야 한다. 앞에서 말한 것 처럼 입력하는 데이터의 수와 비교해서 배열의 크기가 클 수록 충돌 확률은 낮아진다. 통계적으로 입력한 데이터의 수가 배열의 크기를 75% 넘지 않으면 해시 인덱스는 자주 충돌하지 않는다. 반대로 75%를 넘으면 자주 충돌하기 시작한다. 배열의 크기를 크게 만들면 해시 충돌은 줄어서 성능은 좋아지지만, 많은 메모리가 낭비된다. 반대로 배열의 크기를 너무 작게 만들면 해시가 자주 충돌해서 성능이 나빠진다. 상황에 따라 다르겠지만 보통 75%를 적절한 크기로 보고 기준으로 잡는 것이 효과적이다.


정리
해시 인덱스를 사용하는 방식은 최악의 경우 O(n)의 성능을 보인다. 하지만 확률적으로 보면 어느 정도 넓게 퍼지기 때문에 평균으로 보면 대부분 O(1)의 성능을 제공한다. 해시 충돌이 가끔 발생해도 내부에서 값을 몇 번만 비교하는 수준이기 때문에 대부분의 경우 매우 빠르게 값을 찾을 수 있다.


HashSet.

Set의 성능을 해시 알고리즘을 통해 평균 O(1)으로 개선한 자료구조이다. 해시 알고리즘을 사용한 덕분에 등록, 검색, 삭제 모두 평균 O(1)로 연산 속도를 크게 개선할 수 있다.


해시 함수(Hash Function)
해시 함수는 임의의 길이의 데이터를 입력으로 받아, 고정된 길이의 해시값(해시 코드)을 출력하는 함수이다. (ex. 문자열 to 정수)


해시 코드(Hash Code)
해시 코드는 데이터를 대표하는 값을 뜻한다. 보통 해시 함수를 통해 만들어진다. (ex. 문자열 to 정수)


해시 인덱스(Hash Index)
해시 인덱스는 데이터의 저장 위치를 결정하는데, 주로 해시 코드를 사용해서 만든다. 보통 해시 코드의 결과를 배열의 크기로 나누어서 구한다. (Ex. 정수 to 나머지)


자바의 hashCode()

모든 타입을 해시 자료구조에 저장하려면, 정수 int , Integer 뿐만 아니라 char , String , Double , Boolean 등 수 많은 타입, 그리고 개발자가 직접 정의한 Member , User 와 같은 사용자 정의 타입의 객체가 숫자 해시 코드를 제공할 수 있어야 한다.


Object.hashCode()

Object 클래스는 모든 클래스의 최상위 클래스이다. 따라서 자바에서는 모든 객체가 자신만의 해시 코드를 표현할 수 있는 기능을 제공하기 위해 Object에 hashCode() 메서드가 존재한다.


public class Object {
	public int hashCode();
}

  • 이 메서드를 그대로 사용하지는 않고, 하위 클래스에서 보통 오버라이딩하여 사용한다.
  • 이 메서드의 기본 구현은 객체의 참조값을 기반으로 해시 코드를 생성한다.
  • 쉽게 이야기해서 객체의 인스턴스가 다르면 해시 코드도 다르다.

public class Member {
	
	private String id;
	
	// ...
	// IDE가 자동 완성 해준 hashCode(), equals()
	@Override
	public boolean equals(Object o) {
		if (this == o) return true;
		if (o == null || getClass() != o.getClass()) return false;
		Member member = (Member) o;
		return Objects.equals(id, member.id);
	}

	@Override
	public int hashCode() {
		return Objects.hash(id);
	}
}

  • 자바 기본 클래스는 이미 hashCode() 메서드가 오버라이딩되어있다.
  • 데이터(논리적 비교의 대상)의 값이 같으면 같은 해시 코드를 반환한다.
    • 값이 중복되지 않는 자료구조에서 값이 존재하는지를 체크하는데 hash가 등장했는데, 값이 같은데 다른 해시 코드를 반환하는 것은 말이 안된다.
    • 즉, 동등하면 같은 해시 코드를 반환해야 한다.
  • Member 의 경우 회원의 id 가 같으면 논리적으로 같은 회원이므로, 동등성 비교의 기준이 된다.
    • 중요! 이에 맞게 equals() 를 재정의해야한다. equals()를 통해 논리적 동등성을 정의해주는 거다.
    • 그래야 hashcode를 생성할 때 논리적 동등성이 제대로 정의된 equals()를 사용할 수 있다.
  • hashCode() 를 재정의할 때 Objects.hash() 에 해시 코드로 사용할 값을 지정해주면 쉽게 해시 코드를 생성할 수 있다.
    • hashCode() 를 재정의하지 않으면 Object 가 기본으로 제공하는 hashCode() 를 사용하게 된다. 이것은 객체의 참조값을 기반으로 해시 코드를 제공한다. 따라서 회원의 id 가 같아도 인스턴스가 다르면 다른 해시 코드를 반환하게 된다.

따라서 해시 자료 구조를 사용할 때는 hashCode() 는 물론이고, equals()도 반드시 재정의해야 한다.
만약 equals()를 재정의하지 않으면, Object 가 기본으로 제공하는 참조값 기반의 equals()가 동작하여 문제가 발생한다. 동등한 객체여도 참조값이 달라 다른 해시 코드를 생성하거나, 동등하지 않다고 반환할 수 있다.


hashIndex()

  • 해시 코드를 해시 인덱스로 변환했을 때 음수가 되지 않도록 주의해줘야 한다.

해시 함수 설계

자바의 해시 함수는 문자의 숫자를 단순히 더하기만 하는 것이 아니라 내부에서 복잡한 추가 연산을 수행한다. 복잡한 추가 연산으로 다양한 범위의 해시 코드가 만들어지므로 해시가 충돌할 가능성이 낮아지고, 결과적으로 해시 자료 구조를 사용할 때 성능이 개선된다.


좋은 해시 함수는 해시 코드가 한 곳에 뭉치지 않고 균일하게 분포하는 것이 좋다. 그래야 해시 인덱스도 골고루 분포되어서 해시 자료 구조의 성능을 최적화할 수 있다. 이런 해시 함수를 직접 구현하는 것은 쉽지 않다. 자바가 제공하는 해시 함수들을 사용하면 이런 부분을 걱정하지 않고 최적화 된 해시 코드를 구할 수 있다.


자바 Set 인터페이스


자바의 Set 인터페이스는 java.util 패키지의 컬렉션 프레임워크에 속하는 인터페이스 중 하나이다. Set 인터페이스는 중복을 허용하지 않는 유일한 요소의 집합을 나타낸다. 그러다보니, 특정 요소가 집합에 있는지 여부를 확인하는데 최적화되어 있다.


주요 메서드

  • add(E e) 지정된 요소를 세트에 추가한다(이미 존재하는 경우 추가하지 않음).
  • addAll(Collection<? extends E> c) 지정된 컬렉션의 모든 요소를 세트에 추가한다.
  • contains(Object o) 세트가 지정된 요소를 포함하고 있는지 여부를 반환한다.
  • containsAll(Collection<?> c) 세트가 지정된 컬렉션의 모든 요소를 포함하고 있는지 여부를 반환한다.
  • remove(Object o) 지정된 요소를 세트에서 제거한다.
  • removeAll(Collection<?> c) 지정된 컬렉션에 포함된 요소를 세트에서 모두 제거한다.
  • retainAll(Collection<?> c) 지정된 컬렉션에 포함된 요소만을 유지하고 나머지 요소는 세트에서 제거한다.
  • clear() 세트에서 모든 요소를 제거한다.
  • size() 세트에 있는 요소의 수를 반환한다.
  • isEmpty() 세트가 비어 있는지 여부를 반환한다.
  • iterator() 세트의 요소에 대한 반복자를 반환한다.
  • toArray() 세트의 모든 요소를 배열로 반환한다.
  • toArray(T[] a) 세트의 모든 요소를 지정된 배열로 반환한다.

HashSet

  • 구현: 해시 자료 구조를 사용해서 요소를 저장한다.
  • 순서: 요소들은 특정한 순서 없이 저장된다. 즉, 요소를 추가한 순서를 보장하지 않는다.
  • 시간 복잡도: HashSet 의 주요 연산(추가, 삭제, 검색)은 평균적으로 O(1) 시간 복잡도를 가진다.
  • 용도: 데이터의 유일성만 중요하고, 순서가 중요하지 않은 경우에 적합하다.

LinkedHashSet

  • 구현: LinkedHashSet 은 HashSet 에 연결 리스트를 추가해서 요소들의 순서를 유지한다.
  • 순서: 요소들은 추가된 순서대로 유지된다. 즉, 순서대로 조회 시 요소들이 추가된 순서대로 반환된다.
  • 시간 복잡도: LinkedHashSet도 HashSet 과 마찬가지로 주요 연산에 대해 평균 O(1) 시간 복잡도를 가진다.
  • 용도: 데이터의 유일성과 함께 삽입 순서를 유지해야 할 때 적합하다.
  • 참고: 연결 링크를 유지해야 하기 때문에 HashSet 보다는 조금 더 무겁다.

TreeSet

  • 구현: TreeSet 은 이진 탐색 트리를 개선한 레드-블랙 트리를 내부에서 사용한다.
    • 최악의 경우에도 O(logn) 의 성능을 제공한다.
  • 순서: 요소들은 정렬된 순서로 저장된다. 순서의 기준은 비교자(Comparator )로 변경할 수 있다.
  • 시간 복잡도: 주요 연산들은 O(log n) 의 시간 복잡도를 가진다. 따라서 HashSet 보다는 느리다.
  • 용도: 데이터들을 정렬된 순서로 유지하면서 집합의 특성을 유지해야 할 때 사용한다. 예를 들어, 범위 검색이나 정렬된 데이터가 필요한 경우에 유용하다. 참고로 입력된 순서가 아니라 데이터 값의 순서이다. 예를 들어 3, 1, 2 를 순서대로 입력해도 1, 2, 3 순서로 출력된다.

자바 HashSet과 최적화 - rehashing

  • 자바의 HashSet 은 우리가 직접 구현한 내용과 거의 같지만 최적화를 추가로 진행한다.
    • 데이터의 양이 배열 크기의 75%를 넘어가면 배열의 크기를 2배로 늘리고 2배 늘어난 크기를 기준으로 모든 요소에 해시 인덱스를 다시 적용한다.
    • 해시 인덱스를 다시 적용하는 시간이 걸리지만, 결과적으로 해시 충돌 가능성이 줄어든다.
    • 자바 HashSet 의 기본 크기는 16 이다.
    • 이 과정을 재해싱(rehashing)이라 한다.

자바 Set 정리

실무에서는 Set 이 필요한 경우 HashSet 을 가장 많이 사용한다고 한다. 그리고 입력 순서 유지, 값 정렬의 필요에 따라서LinkedHashSet , TreeSet 을 선택하면 된다.


Map 인터페이스


메서드 설명
put(K key, V value) 지정된 키와 값을 맵에 저장한다. (같은 키가 있으면 값을 변경)
putAll(Map<? extends K,? extends V> m) 지정된 맵의 모든 매핑을 현재 맵에 복사한다.
putIfAbsent(K key, V value) 지정된 키가 없는 경우에 키와 값을 맵에 저장한다.
get(Object key) 지정된 키에 연결된 값을 반환한다.
getOrDefault(Object key, V defaultValue) 지정된 키에 연결된 값을 반환한다. 키가 없는 경우 defaultValue 로 지정한 값을 대신 반환한다.
remove(Object key) 지정된 키와 그에 연결된 값을 맵에서 제거한다.
clear() 맵에서 모든 키와 값을 제거한다.
containsKey(Object key) 맵이 지정된 키를 포함하고 있는지 여부를 반환한다.
containsValue(Object value) 맵이 하나 이상의 키에 지정된 값을 연결하고 있는지 여부를 반환한다.
keySet() 맵의 키들을 Set 형태로 반환한다.
values() 맵의 값들을 Collection 형태로 반환한다.
entrySet() 맵의 키-값 쌍을 Set<Map.Entry<K,V>> 형태로 반환한다.
size() 맵에 있는 키-값 쌍의 개수를 반환한다.
isEmpty() 맵이 비어 있는지 여부를 반환한다.

키 목록 조회
Set<String> keySet = studentMap.keySet()
Map 의 키는 중복을 허용하지 않는다. 따라서 Map 의 모든 키 목록을 조회하는 keySet() 을 호출하면, 중복을 허용하지 않는 자료 구조인 Set 을 반환한다


키와 값 목록 조회
Map 은 키와 값을 보관하는 자료 구조이다. 따라서 키와 값을 하나로 묶을 수 있는 방법이 필요하다. 이때 Entry 를 사용한다. Entry 는 키-값의 쌍으로 이루어진 간단한 객체이다. Entiry 는 Map 내부에서 키와 값을 함께 묶어서 저장할 때 사용한다.
(Entry 는 Map 내부에 있는 인터페이스이다)


해시를 사용해서 키와 값을 저장하는 자료 구조를 일반적으로 해시 테이블이라 한다.


값 목록 조회
Collection<Integer> values = studentMap.values()
Map 의 값 목록을 중복을 허용한다. 중복도 가능하고, 순서도 보장되지 않기 때문에, 단순히 값의 모음이라는 의미의 상위 인터페이스인 Collection으로 반환한다.


같은 키로 다른 데이터를 저장
Map 에 값을 저장할 때 같은 키에 다른 값을 저장하면 기존 값을 교체한다


키가 없는 경우에만 추가
if (!studentMap.containsKey("studentA”)) 이런식으로 조건문을 사용할 수도 있지만, putIfAbsent() 메서드를 사용하여 키가 없는 경우에만 데이터를 저장하도록 할 수 있다.

  • studentMap.putIfAbsent("studentA", 100);

HashMap

  • 구조: HashMap 은 해시를 사용해서 요소를 저장한다. 키(Key ) 값은 해시 함수를 통해 해시 코드로 변환되고, 이 해시 코드는 데이터를 저장하고 검색하는 데 사용된다.
  • 특징: 삽입, 삭제, 검색 작업은 해시 자료 구조를 사용하므로 일반적으로 상수 시간(O(1) )의 복잡도를 가진다.
  • 순서: 순서를 보장하지 않는다.

LinkedHashMap

  • 구조: LinkedHashMap 은 HashMap 과 유사하지만, 연결 리스트를 사용하여 삽입 순서 또는 최근 접근 순서에 따라 요소를 유지한다.
  • 특징: 입력 순서에 따라 순회가 가능하다. HashMap 과 같지만 입력 순서를 링크로 유지해야 하므로 조금 더 무겁다.
  • 성능: HashMap 과 유사하게 대부분의 작업은 O(1) 의 시간 복잡도를 가진다.
  • 순서: 입력 순서를 보장한다.

TreeMap

  • 구조: TreeMap 은 레드-블랙 트리를 기반으로 한 구현이다.
  • 특징: 모든 키는 자연 순서 또는 생성자에 제공된 Comparator 에 의해 정렬된다.
  • 성능: get , put , remove 와 같은 주요 작업들은 O(log n) 의 시간 복잡도를 가진다.
  • 순서: 키는 정렬된 순서로 저장된다.

정리하면

  • HashMap : 입력한 순서를 보장하지 않는다.
  • LinkedHashMap : 키를 기준으로 입력한 순서를 보장한다.
  • TreeMap : 키 자체의 데이터 값을 기준으로 정렬한다.

실무에서는 Map 이 필요한 경우 HashMap 을 많이 사용한다. 그리고 순서 유지, 정렬의 필요에 따라서
LinkedHashMap , TreeMap 을 선택하면 된다.


Stack - 사용 금지

메서드

  • stack.peek() : 다음 꺼낼 요소 확인(꺼내지 않고 단순 조회만)
  • stack.pop() : 스택 탑에 있는 요소 빼기
  • stack.push() : 스택에 요소 넣기

주의!- Stack 클래스는 사용하지 말자
자바의 Stack 클래스는 내부에서 Vector 라는 자료 구조를 사용한다. 이 자료 구조는 자바 1.0에 개발되었는데, 지금은 사용되지 않고 하위 호환을 위해 존재한다. 지금은 더 빠른 좋은 자료 구조가 많다. 따라서 Vector 를 사용하는 Stack도 사용하지 않는 것을 권장한다. 대신에 이후에 설명할 Deque 를 사용하는 것이 좋다.


Queue 인터페이스

전통적으로 큐에 값을 넣는 것을 offer 라 하고, 큐에서 값을 꺼내는 것을 poll 이라 한다.
(자바 진영에서는 이렇게 메서드 이름이 맞춰져있다. C++에서는 push, pop을 쓴다)



참고로 LinkedList 는 Deque 와 List 인터페이스를 모두 구현한다.

public class LinkedList<E> extends AbstractSequentialList<E>
implements List<E>, Deque<E>, Cloneable, java.io.Serializable {}

Deque 인터페이스

Deque는 일반적인 큐(Queue)와 스택(Stack)의 기능을 모두 포함하고 있다.


Deque 구현체와 성능 테스트

Deque 의 대표적인 구현체는 ArrayDeque , LinkedList 가 있다. 이 둘 중에 ArrayDeque 가 모든 면에서 더 빠르다.


둘의 차이는 ArrayList vs LinkedList 의 차이와 비슷한데, 작동 원리가 하나는 배열을 하나는 동적 노드 링크를 사용하기 때문이다.
ArrayDeque 는 추가로 특별한 원형 큐 자료 구조를 사용하는데, 덕분에 앞, 뒤 입력 모두 O(1)의 성능을 제공한다. 물론 LinkedList 도 앞 뒤 입력 모두 O(1)의 성능을 제공한다.


Deque와 Stack, Queue

Deque 는 양쪽으로 데이터를 입력하고 출력할 수 있다. 즉, 스택과 큐의 역할을 모두 수행할 수 있다. Deque 를 Stack 과 Queue로 사용하기 위한 메서드 이름까지 제공한다.



Deque 에서 Stack 을 위한 메서드 이름까지 제공하는 것을 확인할 수 있다. 자바의 Stack 클래스는 성능이 좋지 않고 하위 호환을 위해서 남겨져 있다. Stack 자료 구조가 필요하면 Deque 에 ArrayDeque 구현체를 사용하자.



Deque 에서 Queue 을 위한 메서드 이름까지 제공하는 것을 확인할 수 있다. Deque 인터페이스는 Queue 인터페이스의 자식이기 때문에, 단순히 Queue 의 기능만 필요하면 Queue 인터페이스를 사용하고, 더 많은 기능이 필요하다면 Deque 인터페이스를 사용하면 된다. 그리고 구현체로 성능이 빠른 ArrayDeque 를 사용하자.


순회

각각의 자료 구조마다 순회하는 방법이 서로 다르기 때문에, 각 자료 구조의 순회 방법을 배워야 한다. 순회 방법을 배우려면 내부 구조를 자세히 알아야 한다. 하미나 자료 구조를 사용하는 개발자 입장에서 보면 단순히 자료 구조에 들어있는 모든 데이터에 순서대로 접근해서 출력하거나 계산하고 싶을 뿐이다.


자료 구조의 구현과 관계 없이 모든 자료 구조를 동일한 방법으로 순회할 수 있는 일관성 있는 방법이 있다면, 자료 구조를 사용하는 개발자 입장에서 매우 편리할 것이다. 자바는 이런 문제를 해결하기 위해 Iterable 과 Iterator 인터페이스를 제공한다.


Iterable, Iterator

Iterable : "반복 가능한"이라는 뜻이다.
Iterator : "반복자"라는 뜻이다.


public interface Iterable<T> {
	Iterator<T> iterator();
}

단순히 Iterator 반복자를 반환한다.


public interface Iterator<E> {
	boolean hasNext();
	E next();
}

// 예시
public class MyArrayIterator implements Iterator<Integer> {

// 예시
public class MyArray implements Iterable<Integer> {

    private int[] numbers;

    public MyArray(int[] numbers) {
        this.numbers = numbers;
    }

    @Override
    public Iterator<Integer> iterator() {
        return new MyArrayIterator(numbers);
    }
}

Iterable을 구현한 자료구조에서 Iterator를 받은 다음, 그 Iterator를 가지고 순회하며 ㄴ된다.


  • hasNext() : 다음 요소가 있는지 확인한다. 다음 요소가 없으면 false 를 반환한다.
  • next() : 다음 요소를 반환한다. 내부에 있는 위치를 다음으로 이동한다.

자료구조에 있는 데이터를 처음부터 끝까지 순회하는 방법은, 자료 구조에 다음 요소가 있는지 물어보고, 있으면 다음 요소를 꺼내는 과정을 반복하면 된다.

향상된 for문

Iterable과 향상된 for문(Enhanced For Loop)

Iterable , Iterator 를 사용하면 또 하나의 큰 장점을 얻을 수 있다.
바로 for-each문으로 불리는 향상된 for문을 사용할 수 있다. 향상된 for문은 자료 구조를 순회하는 것이 목적이다. 자바는 Iterable 인터페이스를 구현한 객체에 대해서 향상된 for문을 사용할 수 있게 해준다.

for (int value : myArray) {
	System.out.println("value = " + value);
}

위 코드를 자바 컴파일러가 아래와 같이 코드를 변경해준다.

while (iterator.hasNext()) {
	Integer value = iterator.next();
	System.out.println("value = " + value);
}

자바가 제공하는 Iterable, Iterator

  • 자바는 컬렉션 프레임워크를 사용하는 개발자가 편리하고 일관된 방법으로 자료 구조를 순회할 수 있도록Iterable 인터페이스를 제공하고, 이미 각각의 구현체에 맞는 Iterator도 다 구현해두었다.
  • 자바 Collection 인터페이스의 상위에 Iterable 이 있다는 것은 모든 컬렉션을 Iterable 과Iterator 를 사용해서 순회할 수 있다는 뜻이다.
  • Map 의 경우 Key 뿐만 아니라 Value 까지 있기 때문에 바로 순회를 할 수는 없다. keySet() , values() 를 호출하면 Set , Collection 을 반환하기 때문에 Key 나 Value 를 정해서 순회할 수 있다. entrySet()도 순회가 가능하다.


인터페이스 다형성 이용

private static void printAll(Iterator<Integer> iterator) {
	System.out.println("iterator = " + iterator.getClass());
	while (iterator.hasNext()) {
		System.out.println(iterator.next());
	}
}

private static void foreach(Iterable<Integer> iterable) {
	System.out.println("iterable = " + iterable.getClass());
	for (Integer i : iterable) {
		System.out.println(i);
	}
}

  • Iterator , Iterable 은 인터페이스이다. 따라서 다형성을 적극 활용할 수 있다.
  • printAll() , foreach() 메서드는 새로운 자료 구조가 추가되어도 해당 자료 구조가 Iterator ,Iterable 만 구현하고 있다면 코드 변경 없이 사용할 수 있다.

참고

  • ArrayList 의 Iterator 는 ArrayList 의 중첩 클래스이다.
  • java.util.HashMap$KeyIterator : HashSet 자료 구조는 사실은 내부에서 HashMap 자료 구조를 사용한다. HashMap 자료 구조에서 Value 를 사용하지 않으면 HashSet 과 같다.

정렬 - Comparable, Comparator

배열을 정렬할 때는 Arrays.sort() 를 사용하면 배열에 들어있는 데이터를 순서대로 정렬할 수 있다.


자바에서 사용하는 정렬 알고리즘
자바는 초기에는 퀵소트를 사용했다가 지금은 데이터가 작을 때(32개 이하)는 듀얼 피벗 퀵소트(Dual-Pivot QuickSort)를 사용하고, 데이터가 많을 때는 팀소트(TimSort)를 사용한다. 이런 알고리즘은 평균 O(n log n)의 성능을 제공한다.


비교자 - Comparator

두 값을 비교할 때 비교 기준을 직접 제공할 수 있다.


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

  • 두 인수를 비교해서 결과 값을 반환하면 된다.
    • 첫 번째 인수가 더 작으면 음수, 예(-1 )
    • 두 값이 같으면 0
    • 첫 번째 인수가 더 크면 양수, 예(1 )

	static class AscComparator implements Comparator<Integer> {
        @Override
        public int compare(Integer o1, Integer o2) {
            return (o1 < o2) ? -1 : ((o1 == o2) ? 0 : 1);
        }
    }

    static class DescComparator implements Comparator<Integer> {
        @Override
        public int compare(Integer o1, Integer o2) {
            return ((o1 < o2) ? -1 : ((o1 == o2) ? 0 : 1)) * -1;
        }
    }


Arrays.sort() 를 사용할 때 비교자(Comparator )를 넘겨주면 알고리즘에서 어떤 값이 더 큰지 두 값을 비교할 때, 비교자를 사용한다.


정렬을 반대로

new AscComparator().reversed()

정렬을 반대로 하고 싶으면 reversed() 메서드를 사용하면 된다. 이렇게 하면 비교의 결과를 반대로 변경한
다. 앞서 설명한 -1 을 곱한 것과 같은 결과가 나온다.


Comparable, Comparator

직접 만든 객체를 정렬하려면 어떻게 해야 할까? 내가 만든 객체이기 때문에 정렬을 할 때 내가 만든 두 객체 중에 어떤 객체가 더 큰지 알려줄 방법이 있어야 한다. 이때는 Comparable 인터페이스를 구현하면 된다. (객체에 비교 기능을 추가해 준다.)


public interface Comparable<T> {
	public int compareTo(T o);
}

package collection.compare;

public class MyUser implements Comparable<MyUser> {
    private String id;
    private int age;
	// 생략 
    @Override
    public int compareTo(MyUser o) {
        return this.age < o.age ? -1 : (this.age == o.age ? 0 : 1);
    }
}

Arrays.sort(array)를 사용하여 MyUser array 정렬
기본 정렬을 시도한다. 이때는 객체가 스스로 가지고 있는 Comparable 인터페이스를 사용해서 비교한다.
MyUser 가 구현한 대로 나이(age ) 오름차순으로 정렬된 것을 확인할 수 있다. MyUser 의 자연적인 순서를 사용했다.


Arrays.sort(array, Comparator)
기본 정렬이 아니라 정렬 방식을 지정하고 싶다면 Arrays.sort 의 인수로 비교자(Comparator )를 만들어서 넘겨주면 된다. 이렇게 비교자를 따로 전달하면 객체가 기본으로 가지고 있는 Comparable 을 무시하고, 별도로 전달한 비교자를 사용해서 정렬한다.


MyUser 배열을 아이디로 정렬하고 싶다면 IdComparator 를 넘겨주면 된다.


Comparable, Comparator 정리
객체의 기본 정렬 방법은 객체에 Comparable 를 구현해서 정의한다. 이렇게 하면 객체는 이름 그대로 비교할 수 있는 객체가 되고 기본 정렬 방법을 가진다. 그런데 기본 정렬 외에 다른 정렬 방법을 사용해야 하는 경우 비교자 (Comparator )를 별도로 구현해서 정렬 메서드에 전달하면 된다. 이 경우 전달한 Comparator 가 항상 우선권을 가진다. 자바가 제공하는 Integer , String 같은 기본 객체들은 대부분 Comparable 을 구현해 두었다.


자료구조 정렬

정렬은 배열 뿐만 아니라 순서가 있는 List 같은 자료 구조에도 사용할 수 있다.



Collections.sort(list)

  • 리스트는 순서가 있는 컬렉션이므로 정렬할 수 있다.
  • 이 메서드를 사용하면 기본 정렬이 적용된다.
  • 하지만 이 방식보다는 객체 스스로 정렬 메서드를 가지고 있는 list.sort() 사용을 더 권장한다. 참고로 둘의 결과는 같다.

list.sort(null)

  • 별도의 비교자가 없으므로 Comparable로 비교해서 정렬한다.
  • 자연적인 순서로 비교한다.
  • 자바 1.8 부터 사용

Collections.sort(list, new IdComparator())

  • 별도의 비교자로 비교하고 싶다면 다음 인자에 비교자를 넘기면 된다.
  • 하지만 이 방식보다는 객체 스스로 정렬 메서드를 가지고 있는 list.sort() 사용을 더 권장한다. 참고로 둘의 결과는 같다.

list.sort(new IdComparator())

  • 전달한 비교자로 비교한다.
  • 자바 1.8 부터 사용

Tree 구조와 정렬

TreeSet 과 같은 이진 탐색 트리 구조는 데이터를 보관할 때, 데이터를 정렬하면서 보관한다. 따라서 정렬 기준을 제공하는 것이 필수다.


이진 탐색 트리는 데이터를 저장할 때 왼쪽 노드에 저장해야 할 지, 오른쪽 노드에 저장해야 할 지 비교가 필요하다. 따라서 TreeSet , TreeMap 은 Comparable 또는 Comparator 가 필수이다


TreeSet<MyUser> treeSet1 = new TreeSet<>();
treeSet1.add(myUser1);
treeSet1.add(myUser2);
treeSet1.add(myUser3);
System.out.println("Comparable 기본 정렬");

TreeSet<MyUser> treeSet2 = new TreeSet<>(new IdComparator());
treeSet2.add(myUser1);
treeSet2.add(myUser2);
treeSet2.add(myUser3);
System.out.println("IdComparator 정렬");

정리
객체의 정렬이 필요한 경우 Comparable 을 통해 기본 자연 순서를 제공하자.(자바 기본 타입들은 이미 구현되어 있다) 자연 순서 외에 다른 정렬 기준이 추가로 필요하면 Comparator 를 제공하자.


컬렉션 유틸


Collections 정렬 관련 메서드

  • max : 정렬 기준으로 최대 값을 찾아서 반환한다.
  • min : 정렬 기준으로 최소 값을 찾아서 반환한다.
  • shuffle : 컬렉션을 랜덤하게 섞는다.
  • sort : 정렬 기준으로 컬렉션을 정렬한다.
  • reverse : 정렬 기준의 반대로 컬렉션을 정렬한다. (컬렉션에 들어있는 결과를 반대로 정렬한다.)

편리한 컬렉션 생성

List<Integer> list = List.of(1, 2, 3);
Set<Integer> set = Set.of(1, 2, 3);
Map<Integer, String> map = Map.of(1, "one", 2, "two");

  • List.of(...) : 를 사용하면 컬렉션을 편리하게 생성할 수 있다. 단 이때는 가변이 아니라 불변 컬렉션이 생성된다.
    • List , Set , Map 모두 of() 메서드를 지원한다.
  • 불변 컬렉션은 변경할 수 없다. 변경 메서드를 호출하면 UnsupportedOperationException 예외가 발생한다.
    • 위 예제에서 list.add(4); 호출 시 예외 발생


불변 컬렉션과 가변 컬렉션 전환

//불변 리스트 생성
List<Integer> list = List.of(1, 2, 3);

//가변 리스트
ArrayList<Integer> mutableList = new ArrayList<>(list);
mutableList.add(4);

//가변 리스트로부터 불변 리스트 생성
//불변 리스트
List<Integer> unmodifiableList = Collections.unmodifiableList(mutableList);

  • 불변 리스트를 가변 리스트로 전환하려면 new ArrayList<>() 를 사용하면 된다.
  • 가변 리스트를 불변 리스트로 전환하려면 Collections.unmodifiableList() 를 사용하면 된다.
    • 물론 다양한 unmodifiableXxx() 가 존재한다.

빈 리스트 생성

//빈 가변 리스트 생성
List<Integer> list1 = new ArrayList<>();
List<Integer> list2 = new LinkedList<>();

//빈 불변 리스트 생성
List<Integer> list3 = Collections.emptyList(); //자바5
List<Integer> list4 = List.of(); //자바9

  • 빈 가변 리스트는 원하는 컬렉션의 구현체를 직접 생성하면 된다.
  • 빈 불변 리스트는 2가지 생성 방법이 있다.
    • Collections.emptyList() : 자바5부터 제공되는 기능이다.
    • List.of() : 자바9부터 제공되는 최신 기능이다.
    • List.of() 가 더 간결하고, List.of(1,2,3) 도 불변이기 때문에 사용법에 일관성이 있다. 자바 9 이상을 사용한다면 이 기능을 권장한다.

Arrays.asList()

  • Arrays.asList 메서드를 사용해도 다음과 같이 리스트를 생성할 수 있다.
    • List<Integer> list = Arrays.asList(1, 2, 3);
  • 참고로 이 메서드는 자바 1.2부터 존재했다. 자바 9를 사용한다면 List.of() 를 권장한다.
  • Arrays.asList() 로 생성된 리스트는 고정된 크기를 가지지만, 요소들은 변경할 수 있다. 즉, 리스트의 길이는 변경할 수 없지만, 기존 위치에 있는 요소들을 다른 요소로 교체할 수 있다.
    • set() 을 통해 요소를 변경할 수 있다.
    • add() , remove() 같은 메서드를 호출하면 예외가 발생한다. 크기를 변경할 수 없다.
      • java.lang.UnsupportedOperationException 발생
  • 고정도 가변도 아닌 애매한 리스트이다.

정리하면 일반적으로 List.of() 를 사용하는 것을 권장한다. 다음과 같은 경우 Arrays.asList() 를 선택할 수있다.

  • 변경 가능한 요소: 리스트 내부의 요소를 변경해야 하는 경우(단, 리스트의 크기는 변경할 수 없음).
  • 하위 호환성: Java 9 이전 버전에서 작업해야 하는 경우

멀티스레드 동기화

ArrayList<Integer> list = new ArrayList<>();
list.add(1);
list.add(2);
list.add(3);

List<Integer> synchronizedList = Collections.synchronizedList(list);
  • Collections.synchronizedList 를 사용하면 일반 리스트를 멀티스레드 상황에서 동기화 문제가 발생하지 않는 안전한 리스트로 만들 수 있다.
  • 동기화 작업으로 인해 일반 리스트보다 성능은 더 느리다.

Collection 인터페이스 정리

구체적인 컬렉션 인터페이스들은 모두 Collection 인터페이스를 확장(extend)하여, 공통된 메서드들을 상속받고 추가적인 기능이나 특성을 제공한다. 이로 인해 일관성, 재사용성을 높여준다.


Collection 인터페이스의 주요 메서드

Collection 인터페이스에는 다음과 같은 주요 메서드들이 포함된다.

  • add(E e) : 컬렉션에 요소를 추가한다.
  • remove(Object o) : 주어진 객체를 컬렉션에서 제거한다.
  • size() : 컬렉션에 포함된 요소의 수를 반환한다.
  • isEmpty() : 컬렉션이 비어 있는지 확인한다.
  • contains(Object o) : 컬렉션이 특정 요소를 포함하고 있는지 확인한다.
  • iterator() : 컬렉션의 요소에 접근하기 위한 반복자를 반환한다.
  • clear() : 컬렉션의 모든 요소를 제거한다.

Collection 은 Map 을 제외한 모든 컬렉션 타입의 부모이다. 따라서 모든 컬렉션을 받아서 유연하게 처리할 수 있다.


참고) 김영한의 실전 자바 - 중급 2편

'Java > Collection' 카테고리의 다른 글

[Java] 32. Set  (0) 2025.01.19
[Java] 31. HashSet  (0) 2025.01.19
[Java] 30. Hash  (0) 2025.01.19
[Java] 29. 컬렉션- ArrayList, LinkedList, List  (0) 2025.01.19
[Java] 28. 제네릭 - Generic(2)  (0) 2025.01.13
'Java/Collection' 카테고리의 다른 글
  • [Java] 32. Set
  • [Java] 31. HashSet
  • [Java] 30. Hash
  • [Java] 29. 컬렉션- ArrayList, LinkedList, List
lumana
lumana
배움을 나누는 공간 https://github.com/bebeis
  • lumana
    Brute force Study
    lumana
  • 전체
    오늘
    어제
    • 분류 전체보기 (463)
      • 개발 일지 (0)
        • Performance (0)
        • TroubleShooting (0)
        • Refactoring (0)
        • Code Style, Convetion (0)
        • Architecture (0)
      • Software Engineering (36)
        • Test (8)
        • 이론 (18)
        • Clean Code (10)
      • Java (72)
        • Basic (5)
        • Core (21)
        • Collection (7)
        • 멀티스레드&동시성 (13)
        • IO, Network (8)
        • Reflection, Annotation (3)
        • Modern Java(8~) (13)
        • JVM (2)
      • Spring (53)
        • Framework (12)
        • MVC (23)
        • Transaction (3)
        • AOP (11)
        • Boot (0)
        • AI (0)
      • DB Access (16)
        • Jdbc (1)
        • JdbcTemplate (0)
        • JPA (14)
        • Spring Data JPA (0)
        • QueryDSL (0)
      • Computer Science (130)
        • Data Structure (27)
        • OS (14)
        • Database (10)
        • Network (21)
        • 컴퓨터구조 (6)
        • 시스템 프로그래밍 (23)
        • Algorithm (29)
      • HTTP (8)
      • Infra (1)
        • Docker (1)
      • 프로그래밍언어론 (15)
      • Programming Language(Sub) (77)
        • Kotlin (1)
        • Python (25)
        • C++ (51)
        • JavaScript (0)
      • FE (11)
        • HTML (1)
        • CSS (9)
        • React (0)
        • Application (1)
      • Unix_Linux (0)
        • Common (0)
      • PS (13)
        • BOJ (7)
        • Tip (3)
        • 프로그래머스 (0)
        • CodeForce (0)
      • Book Review (4)
      • Math (3)
        • Linear Algebra (3)
      • AI (7)
        • DL (0)
        • ML (0)
        • DA (0)
        • Concepts (7)
      • 프리코스 (4)
      • Project Review (6)
      • LegacyPosts (11)
      • 모니터 (0)
      • Diary (0)
  • 블로그 메뉴

    • 홈
    • 태그
    • 방명록
  • 링크

  • 공지사항

  • 인기 글

  • 태그

  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.4
lumana
[자료구조] 자바 Collection 총 정리(자료구조, Iterator, Iterable, Comparator, Comparable)
상단으로

티스토리툴바