[Java] 컬렉션 프레임워크 (2)

2021. 7. 27. 21:56Java

이번 글은 컬렉션 프레임워크에 관한 두 번째 포스팅입니다.

이번 포스팅에선 컬렉션을 read/write 하기 위한 Iterator, Arrays, Comparator/Comparable에 대해 다뤄보겠습니다.

 

Iterator

Iterator는 Collection에 저장된 데이터를 읽을 때 사용하는 표준화된 Interface입니다.

대표 추상 메서드는 hasNext(), next()가 있습니다.

 

Iterator는 인터페이스지만, iterator() 메서드를 호출하면 Iterator 타입의 객체를 생성할 수 있습니다.

단, 1회용이라 한번 쓰고 나면 다시 iterator() 메서드로 다시 생성해야합니다.

Iterator를 사용하면 List나 Set같은 Collection 타입의 어떠한 자료 구조라도 동일하고 표준화된 방법으로 출력이 가능합니다.

따라서 프로그램의 성능 개선으로 인해 자료구조를 변경해야할 때 효과적으로 사용됩니다.

List list = new ArrayList();
list.add("1");
list.add("2");
list.add("3");
list.add("4");

Iterator it = list.iterator();

while(it.hasNext()) {
	Object obj = it.next();
    System.out.println(obj);
}

 

Iterator단방향으로 next()밖에 사용할 수 없지만, ListIterator양방향으로 prev(), next() 함수로 앞뒤 접근이 가능합니다.

 

Map과 Iterator

Map은 간단히 설명하면 Key와 Value 한 쌍으로 데이터가 저장되는 자료구조입니다.

Map에는 iterator() 함수가 없습니다.

따라서 Map의 keySet(), entrySet(), values() 함수를 호출하여 Collection 타입 참조 변수에 일단 저장하고난 뒤에 iterator()함수를 호출하여 출력합니다.

Set eSet = map.entrySet();
Iterator it = eSet.iterator();

 

 

Arrays 유틸 클래스

이전 포스팅에서 못 다뤘는데, Arrays 는 배열을 다루기 위한 static 메서드를 제공하는 유틸 클래스입니다.

다음과 같은 static 메서드들을 제공합니다.

  • toString(): 배열 출력
  • copyOf(), copyOfRange(): 배열 복사
  • fill(), setAll(): 배열 채우기
  • sort(), binarySearch(): 정렬, 검색
  • deepToString(): 다차원 배열 출력
  • deepEquals(): 다차원 배열 비교

그 밖에도 배열을 List 타입으로 변환하거나 람다와 스트림에 관련된 함수(parallelXXX(), spliterator(), stream())들을 제공합니다.

 

Comparator와 Comparable

Comparator와 Comparable은 정렬에 필요한 메서드를 정의한 인터페이스이며,

정렬의 기준(내림차순으로 할지 or 오름차순으로 할지)을 제공하기 위해 사용합니다.

 

Comparable은 Default 정렬 기준을 제공하는 인터페이스이며, compare(Object o1, Object o2)를 멤버로 가집니다.

compare(Object o1, Object o2)는 o1과 o2를 비교하는 추상 메서드 입니다.

Comparator는 Default 정렬 기준 외에 다른 기준으로 정렬하고자 할 때 사용하는 인터페이스이며, compareTo(Object o)를 멤버로 가집니다.

compareTo(Object o)는 o와 this를 비교하는 추상 메서드입니다.

compare()과 compareTo()는 같으면 0, 오른쪽이 크면 음수, 오른쪽이 작으면 양수를 리턴합니다.

 

정렬을 구현하는 sort()함수는 아래와 같이 두가지 방법으로 작성합니다.

static void sort(Object[] arr, Comparator c) {  //(대상, 기준)
	//코드 생략 
}

//arr가 Comparable을 구현하는 객체라면 위의 메서드처럼 파라미터로 Comparator 구현 객체를 파라미터로 안줘도 됨
static void sort(String[] arr) {  
	//코드 생략
}

 

아래는 Default 기준으로 정렬한 코드입니다.

String[] strArr = {"Cat", "Dog", "Lion", "Tiger"};

Arrays.sort(strArr);  //String이 Comparable을 구현한다
System.out.println("strArr = " + Arrays.toString(strArr));

 

아래는 사용자 정의 기준으로 배열을 정렬한 코드입니다.

class Descending implements Comparator{
	public int compare(Object o1, Object o2){
		if(o1 instanceof Comparable && o2 instanceof Comparable){
			Comparable c1 = (Comparable)o1;
			Comparable c2 = (Comparable)o2;
			return c1.compareTo(c2) * -1;
		}
		return -1;
	}
}

String[] strArr = {"Cat", "Dog", "Lion", "Tiger"};

Arrays.sort(strArr, new Descending());
System.out.println("strArr = " + Arrays.toString(strArr));

 

Comparable과 Comparator를 사용하는 이유

위의 설명을 들어도 Comparable과 Comparator를 사용하는 이유를 이해하기 어려울 것이라 예상합니다.

간단히 말하면 Comparable과 Comparator를 사용하는 이유는 Iterator을 사용하는 것과 마찬가지로 결국 코드의 유지보수성을 위해서 입니다.

 

정렬이란 두 값을 비교하여 자리 바꿈하는 것을 반복하는 것입니다.

위에선 sort()로 단순하게 설명했지만,

알고리즘에서 정렬을 구현하는 방법은 매우 다양합니다.(버블 정렬, 삽입 정렬, 선택 정렬, 퀵 정렬 등등...)

정렬의 로직은 이론적으로 불변이지만 정렬의 기준(내림차순으로 할지 or 오름차순으로 할지)은 가변적으로 여지를 남겨놔야 코드를 유지보수할 때 더 편리하게 작업할 수 있습니다.

결국 Comparable과 Comparator는 정렬 로직과 정렬 기준의 책임을 분리하여 보다 변동 사항에 유리한 코드를 작성하기 위해 사용하는 것입니다.

 

 

Ref.

https://www.youtube.com/playlist?list=PLW2UjW795-f6xWA2_MUhEVgPauhGl3xIp 

 

자바의 정석 기초편(2020최신) - YouTube

 

www.youtube.com

 

'Java' 카테고리의 다른 글

[Java] 제네릭  (0) 2021.08.02
[Java] 컬렉션 프레임워크 (3)  (0) 2021.07.28
[Java] 컬렉션 프레임워크 (1)  (0) 2021.07.26
[Java] 추상 클래스와 인터페이스  (0) 2021.07.21
[Java] 객체지향 개념 (2)  (0) 2021.07.20