관리 메뉴

나구리의 개발공부기록

자바의 정석 기초편 ch11 - 24 ~ 33 [Iterator, ListIterator, Enumeration, Map과 Iterator, Arrays, Comparator와 Comparable] 본문

유튜브 공부/JAVA의 정석 기초편(유튜브)

자바의 정석 기초편 ch11 - 24 ~ 33 [Iterator, ListIterator, Enumeration, Map과 Iterator, Arrays, Comparator와 Comparable]

소소한나구리 2023. 12. 11. 15:10

1) Iterator(new ver.), Enumeration(old ver.), ListIterator

  • 컬렉션에 저장된 데이터를 접근(읽기)하는데 사용되는 인터페이스
  • Enumeration은 Iterator의 구버전
  • ListIterator는 Iterator의 접근성을 향상시킨 것(단방향 -> 양방향 / next()와 previous()가 있음)

(1) Iterator 인터페이스의 메서드

  • boolean hasNext() : 읽어 올 요소가 남아있는지 확인, 있으면 true, 없으면 false
  • Object next() : 다음 요소를 읽어 옴, next()를 호출하기 전에 hasNext()를 호출해서 읽어 올 요소가 있는지 확인하는 것이 안전함
  • void remove() : next()로 읽어 온 요소를 삭제, 값을 읽어온 후 삭제하려면 next()로 호출 후 remove()를 호출하면 됨
  • void forEachRemaining(Consumer<? super E> action) : 컬렉션에 남아있는 요소들에 대해 지정된 작업(action)을 수행, 람다식을 사용하는 디폴트 메서드임(Java 8부터 적용)

(2) Enumeration 인터페이스의 메서드

  • boolean hasMoreElements() : 읽어 올 요소가 남아있는지 확인, Iterator의 hasNext()와 동일
  • Object nextElement() : 다음 요소를 읽어옴, Iterator의 next()와 동일

(3) 컬렉션에 저장된 요소들을 읽어오는 방법을 표준화

  • List, Set, Map에서 데이터를 읽는 메서드가 전부 다른데 이를 표준화하여 컬렉션 변경 시 코드를 변경하지 않아도 되는 장점이 있음
  • 컬렉션타입 참조변수.iterator()를 호출하면 1회성으로 Iterator객체를 반환함
  • Iterator는 Collection 인터페이스에 정의 되어 있음 (List, Set이 모두 가지고 있음)
List list = new ArrayList();
Iterator it = list.iterator();	// Iterator객체를 반환

while(it.hasNext()) {	// 읽어올 요소가 있는지 확인
	System.out.println(it.next());
}

 

(4) Iterator 예제

  • ArrayList로 저장된 값을 Iterator객체를 생성하여 값을 출력
  • Iterator는 1회용이기 때문에 반복적으로 출력하고자할 경우 iterator()로 다시 객체를 얻어와야 함
import java.util.*;

class Ex11_5 {
	public static void main(String[] args) {
		ArrayList list = new ArrayList();
		list.add("1");
		list.add("2");
		list.add("3");
		list.add("4");
		list.add("5");

		Iterator it = list.iterator();

		while(it.hasNext()) {
			Object obj = it.next();
			System.out.println(obj);
		}
		
		// iterator는 1회용
		// 1번더 출력하고자 할 때 다시 얻어와야 함
		it = list.iterator();	// 새로운 iterator객체를 얻음

		while(it.hasNext()) {
			Object obj = it.next();
			System.out.println(obj);
		}
		
		// 반복문으로 구성 하면 get메서드가 없는 인터페이스나 클래스를 사용할 경우 구동 안함
		// ex) HashSet클래스 등
		for(int i=0; i<list.size(); i++) {
			Object obj = list.get(i);
			System.out.println(obj);
		}
		
	} // main
}

 

** 참조변수의 타입이 중요한 이유 리마인드

  • 참조변수 타입이 Collection(조상타입)인 경우 생성한 객체가 자손일 때 조상의 멤버 리모콘으로만 객체를 사용 가능
  • 즉, 객체가 자손 객체들로 교체가 되었을 때 작성된 코드를 수정(검토)하지 않아도 작동 할 것이 확실해짐

(5) 예제2

  • 참조변수 타입이 컬렉션이므로 생성할 객체를 TreeSet, HashSet등 무엇으로 바꾸어도 코드가 작동함
import java.util.*;

class Ex11_5 {
	public static void main(String[] args) {
//		HashSet c = new HashSet();
//		TreeSet c = new TreeSet();
		Collection c = new TreeSet(); // 객체를 Hashset, Treeset 무엇으로 바꾸어도 코드가 작동
		c.add("1");
		c.add("2");
		c.add("3");
		c.add("4");
		c.add("5");

		Iterator it = c.iterator();

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

2) Map과 Iterator

  • Map에는 iterator()가 없기때문에 아래의 메서드를 호출한 뒤 iterator()를 메소드체인 형태로 사용할 수 있음
  • keySet(), entrySet() - 반환타입은 Set
  • values() - 반환타입은 Collection 
Map map = new HashMap();
	...
Iterator it = map.entrySet().iterator(); //	entrySet()메서드를 호출하여 iterator호출

// 아래의 두줄이 위의 한줄처럼 선언 가능
Set eSet = map.entrySet();
Iterator it = eSet.iterator();

메소드 체인이 참조변수에 저장되는 형태


3) Arrays

  • 배열을 다루기 편리한 static메서드 제공

(1) 배열의 출력 - toString()

  • 배열의 값을 출력함

 

(2) 배열의 복사 - copyOf(), copyOfRange()

  • 두번째 인수값이 배열의 길이와 같다면 복사 대상에 포함되고 그보다 적으면 복사 대상에 포함되지 않으며 배열의 길이보다 크면 빈 각 배열의 타입의 기본값으로 초기화 됨

 

(3) 배열채우기 - fill(), [setAll() - 람다식 (14장에서 배움)]

  • fill()메소드로 배열의 값을 동일한 값으로 초기화 할 수 있음
  • setAll()메소드는 람다식을 활용하여 복잡한 초기화를 할 수 있음

 

(4) 배열의 정렬과 검색 - sort(), binarySearch()

  • sort()로 정렬 후 binarySearch(이진탐색)로 검색하여 원하는 위치의 값을 조회할 수 있음
  • 이진 탐색은 정렬된 배열에만 가능함
  • sort()는 기본값이 오름차순 정렬임

 

(5) 다차원 배열의 출력 - deepToString()

  • 2차원이상의 배열의 값을 출력할 수 있음

 

(6) 다차원 배열의 비교 - deepEquals()

  • 2차원이상의 배열의 실제 값을 비교할 수 있음

 

(7) 배열을 List로 변환 - asList(Object ...a)

  • ... 표시는 가변매개변수로 매개변수를 여러게 입력해도 된다는 뜻임
  • asList로 생성한 List는 고정크기이기 때문에 추가(쓰기)를 하려면 예외가 발생 됨.
  • 변경 하기 위해서는 배열을 ArrayList객체로 생성하면 됨

 

** 람다와 스트림에 대해서는 14장에서 배움 - parallelXXX(),spliterator(),stream()

 

(8) 예제

  • 위의 메서드들의 간단한 예시와 출력 결과
import java.util.*;

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

		// 배열, 다차원배열 출력
		int[]	arr   = {0,1,2,3,4};
		int[][]	arr2D = {{11,12,13}, {21,22,23}};
		
		System.out.println("arr="+Arrays.toString(arr));
		System.out.println("arr2D="+Arrays.deepToString(arr2D));
		
		// 배열 복사
		int[] arr2 = Arrays.copyOf(arr, arr.length);	// 배열의 길이만큼 복사
		int[] arr3 = Arrays.copyOf(arr, 3);          
		int[] arr4 = Arrays.copyOf(arr, 7);          
		int[] arr5 = Arrays.copyOfRange(arr, 2, 4);	// 인덱스 2~3까지 출력(4안들어감)  
		int[] arr6 = Arrays.copyOfRange(arr, 0, 7);  

		System.out.println("arr2="+Arrays.toString(arr2));
		System.out.println("arr3="+Arrays.toString(arr3));
		System.out.println("arr4="+Arrays.toString(arr4));
		System.out.println("arr5="+Arrays.toString(arr5));
		System.out.println("arr6="+Arrays.toString(arr6));
		
		// 배열 채우기
		int[] arr7 =  new int[5];
		Arrays.fill(arr7, 9);  // arr=[9,9,9,9,9]
		System.out.println("arr7="+Arrays.toString(arr7));

		//배열 채우기 - 람다식(값이 바뀜)
		Arrays.setAll(arr7, i -> (int)(Math.random()*5)+1);
		System.out.println("arr7="+Arrays.toString(arr7));

		for(int i : arr7) {	// 향상된 for문 - 아래의 for문을 간결하게
//		for(int x=0; x<arr7.length; x++) {
//			int i = arr7[x];
			char[] graph = new char[i];
			Arrays.fill(graph, '*');
			System.out.println(new String(graph)+i);
		}

		// 배열, 다차원 배열 비교
		String[][] str2D  = new String[][]{{"aaa","bbb"},{"AAA","BBB"}};
		String[][] str2D2 = new String[][]{{"aaa","bbb"},{"AAA","BBB"}};

		System.out.println(Arrays.equals(str2D, str2D2));     // false
		System.out.println(Arrays.deepEquals(str2D, str2D2)); // true

		// 배열 정렬 및 이진탐색
		char[] chArr = { 'A', 'D', 'C', 'B', 'E' };

		System.out.println("chArr="+Arrays.toString(chArr));
		// 정렬하지 않고 binarySearch = 잘못된 결과
		System.out.println("index of B ="+Arrays.binarySearch(chArr, 'B'));
		System.out.println("= After sorting =");
		Arrays.sort(chArr);	// binarySearch하기전에 반드시 정렬 먼저
		System.out.println("chArr="+Arrays.toString(chArr));
		System.out.println("index of B ="+Arrays.binarySearch(chArr, 'B'));
	}
}

/*
출력결과
arr=[0, 1, 2, 3, 4]
arr2D=[[11, 12, 13], [21, 22, 23]]
arr2=[0, 1, 2, 3, 4]
arr3=[0, 1, 2]
arr4=[0, 1, 2, 3, 4, 0, 0]
arr5=[2, 3]
arr6=[0, 1, 2, 3, 4, 0, 0]
arr7=[9, 9, 9, 9, 9]
arr7=[4, 3, 1, 3, 3]
****4
***3
*1
***3
***3
false
true
chArr=[A, D, C, B, E]
index of B =-2
= After sorting =
chArr=[A, B, C, D, E]
index of B =1
*/

4) Comparator와 Comparable

  • 객체 정렬에 필요한 메서드(정렬기준 제공)를 정의한 인터페이스
  • 정렬 로직은 불변, 정렬 기준은 가변적
  • Comparable : 기본 정렬 기준을 구현하는데 사용
  • Comparator : 기본 정렬 기준 외에 다른 기준으로 정렬하고자 할 때 사용
public interface Comparator {
	int compare(Object o1, Object o2);	// o1, o2두 객체를 비교
                                        // 같으면 0 , 왼쪽이크면 양수, 오른쪽이크면 음수
}

public interface Comparable {
	int compareTo(Object o);	// 주어진 객체(o)를 자신(this)와 비교
}

 

(1) 기본 정렬 기준

  • compare()는 인수값으로 들어온 두 객체를 비교하여 정수값으로 결과를 반환함
  • compareTo()는 인수값으로 들어온 객체를 자기자신과 비교하여 정수값으로 결과를 반환함
  • 두 메서드 동일하게 비교 객체의 값이 같으면 0, 왼쪽 객체가 크면 양수 오른쪽 객체가 크면 음수로 반환됨
public final class Integer extends Number implements Comparable {
	...
	public int compareTo(Integer anotherInteger) {
		int v1 = this.value;
		int v2 = anotherInteger.value;
		// 같으면 0 왼쪽값이 크면1 왼쪽값이 작으면 -1 
		return(v1 < v2 ? -1 : (v1 == v2 ? 0 : 1)); // 3항연산자가 성능이 2~3% 더 좋음
    ...
}
    // 위 3항연산자의 결과를 간단하게 아래처럼 구성 가능
    return v1 - v2;	// 내림차순 정렬하고자 할때는 반대로

 

(2) 정렬 예제

  • Comparator 인터페이스를 구현하여 compare 메서드를 오버라이딩하여 기본 정렬기준인 오름차순을 내림차순으로 변경
import java.util.*;

class Ex11_7 {
	public static void main(String[] args) {
		String[] strArr = {"cat", "Dog", "lion", "tiger"};

		Arrays.sort(strArr); // String의 Comparable구현에 의한 정렬(String의 기본정렬 - 사전순서)
		System.out.println("strArr(기본정렬기준)=" + Arrays.toString(strArr));

		Arrays.sort(strArr, String.CASE_INSENSITIVE_ORDER); // 대소문자 구분안함
		System.out.println("strArr(대소문자구분안함)=" + Arrays.toString(strArr));

		Arrays.sort(strArr, new Descending()); // 역순 정렬
		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 ; // -1을 곱해서 기본 정렬방식의 역으로 변경
                                           // 또는 c2.compareTo(c1)와 같이 순서를 바꿔도 됨
		}
		return -1;
	} 
}

/* 
출력결과
strArr(기본정렬기준)=[Dog, cat, lion, tiger]
strArr(대소문자구분안함)=[cat, Dog, lion, tiger]
strArr(역순(내림차순)정렬)=[tiger, lion, cat, Dog]
*/

 

 

** 출처 : 남궁성의 정석코딩_자바의정석_기초편 유튜브 강의