공부했던 자료 정리하는 용도입니다.

재배포, 수정하지 마세요.

 

 

 

 

Iterator, ListIterator, Enumeration

  컬렉션에 저장된 요소를 접근할 때 사용하는 인터페이스이다.  Enumeration  Iterator 의 구버전이며,  ListIterator  Iterator 의 기능을 향상시킨 것이다. 

 

 

Iterator

  컬렉션 프레임워크에서는 컬렉션에 저장된 요소를 읽어오는 방법이 표준화되어있다.  Iterator 인터페이스에는 컬렉션에 저장된 각 요소에 접근하는 기능이 있고,  Collection 인터페이스에는  Iterator 의 인스턴스를 반환하는  iterator( ) 가 정의되어있다.  iterator( )  Collection 인터페이스에 정의된 메서드이므로  Collection 인터페이스의 자식인  List  Set 에도 포함되어있다. 그래서  List  Set 인터페이스를 구현하는 컬렉션은 각각의 특징에 맞는  iterator( ) 가 이미 정의되어있다. 컬렉션 클래스에 대해  iterator( ) 를 호출하여  Iterator 를 얻은 다음에  while 문 같은 반복문을 사용해서 컬렉션 클래스의 요소들을 읽어올 수 있다. 

 

 

  ■ Iterator인터페이스의 메서드

 

메서드 설  명
boolean hasNext( ) 읽어올 요소가 남아있는지 확인
있으면 true, 없으면 false를 반환
Object next( ) 다음요소를 읽어옴
 next( ) 를 호출하기 전에  hasNext( ) 를 호출해서 읽어올 요소가 있는지 확인하는것이 안전함
void remove( )  next( ) 로 읽어온 요소를 삭제
 next( ) 를 호출한 다음에  remove( ) 를 호출해야함(선택적 기능)

 

 

  ■ 저장된 요소들을 출력하기

 

//참조변수의 타입을 List로 하는것이 편리하다(클래스가 바뀔경우 new의 클래스만 바꾸면 되기 때문)
List list = new ArrayList();	
Iterator it = list.iterator();

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

   List 를 구현한 컬렉션 클래스의 요소들을 불러올 때는 위의 코드같이 하면 된다. 이때  List 에 없고 특정한 클래스에만 있는 메서드를 사용하는 것이 아니라면  List 타입의 참조변수로 선언하는 것이 편리하다.  List 인터페이스를 구현하는 다른 클래스로 변경해야 하는 경우에  new 부분의 클래스만 변경하면 되기 때문이다. (참조변수의 타입이  List 이면  List 에 정의되지 않은 메서드는 사용하지 않았을 것이 확실하기 때문에 뒤의 코드는 검토하지 않아도 된다.)

 

 

Map map = new HashMap();
...
Iterator it = map.keySet().iterator();

 Map 인터페이스를 구현한 컬렉션은 키( key )와 값( value )를 쌍(pair)으로 저장하고 있기 때문에  iterator( ) 를 직접 호출할 수 없고,  keySet( ) 이나  entrySet( ) 과 같은 메서드를 통해서 키와 값을 각각 따로  Set 의 형태로 얻어온 후에  iterator( ) 를 호출해야  Iterator 를 얻을 수 있다.

 

 

 

 

ListIterator와 Enumeration

 

   Enumeration 은 컬렉션 프레임 워크가 만들어지기 이전에 사용하던 것으로  Iterator 의 구버전이다. 호환을 위해서 남겨져 있는 것이기 때문에  Iterator 를 사용하는 것이 좋다.  ListIterator  Iterator 를 상속받아서 기능을 추가한 것으로, 컬렉션의 요소에 접근할 때  Iterator 는 단방향으로만 이동할 수 있는 반면에  ListIterator 는 양방향으로 이동이 가능하다. 그러나  ArrayList 나  LinkedList 와 같이  List 인터페이스를 구현한 컬렉션에서만 사용할 수 있다.

 

 

  ■ ListIterator의 메서드

 

메서드 설  명
void add(Object o) 컬렉션에 새로운 객체( o )를 추가(선택적기능)
boolean hasNext( ) 읽어 올 다음 요소가 남아있는지 확인
있으면 true, 없으면 false를 반환
boolean hasPrevious( ) 읽어올 이전 요소가 남아있는지 확인
있으면 true, 없으면 false를 반환
Object next( ) 다음 요소를 읽어온다.  next( ) 를 호출하기 전에  hasNext( ) 를 호출해서 읽어올 요소가 있는지 확인하는것이 안전하다
Object previous( ) 이전 요소를 읽어온다.  previous( ) 를 호출하기 전에  hasPrevious( ) 를 호출해서 읽어올 요소가 있는지 확인하는것이 안전하다
int nextIndex( ) 다음 요소 index 반환
int previousIndex( ) 이전 요소 index 반환
void remove( )  next( ) 또는  previous( ) 로 읽어온 요소를 삭제
반드시  next( )  previous( ) 를 먼저 호출한 다음에 이 메서드를 호출해야한다 (선택적기능) 특정위치의 요소를 삭제하는 것이 아니라 읽어온 것을 삭제하는 것이기 때문에  next( )  previous( ) 의 호출없이  remove( ) 를 호출하면  IllegalStateException 이 발생한다.
void set(Object o)  next( ) 또는  previous( ) 로 읽어온 요소를 지정된 객체( o )로 변경한다. 반드시  next( )  previous( ) 를 먼저 호출한 다음 이 메서드를 호출해야 한다. (선택적기능)

 

 

public void remove(){
	throw new UnsupportedOperationException();
}

   선택적 기능(optional operation) 이라고 표시된 것들은 반드시 구현하지 않아도 된다. 하지만 인터페이스로부터 상속받은 메서드는 추상 메서드라 메서드의 body를 반드시 만들어주어야 한다. 이때  public void remove( ) { }; 와 같이 구현하는 것보다 위의 코드처럼 예외를 던져서 구현되지 않은 기능이라는 것을 메서드를 호출한 쪽에 알리는 것이 좋다. 그렇지 않으면 호출하는 쪽에서는 소스를 구해보기 전까지는 이 기능이 바르게 동작하지 않는 이유를 알 방법이 없기 때문이다.

 

 

 

 

 


Arrays

  Arrays클래스에는 배열을 다루는 유용한 메서드들이 정의되어있다.

 

 

  ■ 배열 복사 - copyOf( ), copyOfRange( )

int[] arr = {0, 1, 2, 3, 4};
int[] arr2 = Arrays.copyOf(arr, arrlength);	//arr2 = [0, 1, 2, 3, 4]
int[] arr3 = Arrays.copyOf(arr, 3);	//arr3 = [0, 1, 2]
int[] arr4 = Arrays.copyOf(arr, 7);	//arrt4 = [0, 1, 2, 3, 4, 0, 0]
int[] arr5 = Arrays.copyOfRange(arr, 2, 4);	//arr5 = [2, 3], 4는 포함되지 X
int[] arr6 = Arrays.copyOfRange(arr, 0, 7);	//arr6 = [0, 1, 2, 3, 4, 0, 0]

 copyOf( ) 는 배열 전체,  copyOfRange( ) 는 배열의 일부를 복사해서 새로운 배열을 만들어 반환한다.

지정된 범위의 끝은 포함되지 않는다.

 

 

  ■ 배열 채우기 - fill( ), setAll( )

int[] arr = new int[5];
Arrays.fill(arr, 9);	//arr = [9, 9, 9, 9, 9]
Arrays.setAll(arr, () -> (int)(Math.random() * 5) + 1);	//arr = [1, 5, 2, 1, 1]

  fill( ) 은 배열의 모든 요소를 지정된 값으로 채운다.  setAll( ) 은 배열을 채우는 데 사용할 함수형 인터페이스를 매개변수로 받는다. 이 메서드를 호출할 때는 함수형 인터페이스를 구현한 객체를 매개변수로 지정하던가 람다식을 지정해야 한다.

 

 

  ■ 배열 정렬, 검색 - sort( ), binarySearch( )

int[] arr = {3, 2, 0, 1, 4};
int idx = Arrays.binarySearch(arr, 2);	// idx = -5; <- 잘못된 결과

Arrays.sort(arr);	//배열정렬
System.out.println(Arrays.toString(arr));	// [0, 1, 2, 3, 4]
int idx = Arrays.binarySearch(arr, 2);	// idx = 2 <- 올바른 결과

 sort( ) 는 배열을 정렬할 때 사용하고, 배열에 저장된 요소를 검색할 때는  binarySearch( ) 를 사용한다.  binarySearch( ) 는 배열에서 지정된 값이 저장된 위치( index )를 찾아서 반환하는데 반드시 배열이 정렬된 상태여야 올바른 결과를 얻는다. 또한 일치하는 요소들이 여러 개 있다면, 이 중에서 어떤 것의 위치가 반환될지 알 수없다.

 

배열의 첫 번째 요소부터 순서대로 하나씩 검색하는 것을 순차 검색(linear search)이라고 한다. 순차 검색은 배열이 정렬될 필요는 없지만 시간이 많이 걸린다. 반면에 이진 검색(binary search)은 검색할 범위를 절반씩 줄여나가며 검색하기 때문에 검색 속도가 빠르지만 배열이 정렬되어있는 경우에만 사용할 수 있다는 단점이 있다.

 

 

  ■ 문자열 비교, 출력 - equals( ), toString( )

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

   equals( ) 는 두 배열에 저장된 모든 요소를 비교해서 같으면  true , 다른  false 를 반환한다.  equals( ) 는 일차원 배열에만 사용 가능하므로 다차원 배열의 비교에는  deepEquals( ) 를 사용해야 한다. 다차원 배열은  배열의 배열 의 형태로 구성되기 때문에  equals( ) 로 비교하면 문자열을 비교하는 것이 아니라  배열에 저장된 배열의 주소 를 비교하게 된다. 서로 다른 배열은 항상 주소가 다르므로  false 를 결과로 얻는다.

 

 

int[] arr = {0, 1, 2, 3, 4};
int[][] arr2D = {{11, 22}, {21, 22}};

System.out.println(Arrays.toString(arr));	//[0, 1, 2, 3, 4]
System.out.println(Arrays.deepToString(arr2D));	//[[11, 12], [21, 22]]

 toString( ) 으로 배열의 모든 요소를 문자열로 출력할 수 있다.  toString( ) 도 일차원 배열에만 사용할 수 있으므로 다차원 배열에는  deepToString( ) 을 사용해야 한다.  deepToString( ) 은 배열의 모든 요소를 재귀적으로 접근해서 문자열을 구성하므로 2차원뿐만 아니라 3차원 이상의 배열에도 동작한다.

 

 

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

List list = Arrays.asList(new Integer[]{1,2,3,4,5});	//list = [1, 2, 3, 4, 5]
List list = Arrays.asList(1,2,3,4,5);	//list = [1, 2, 3, 4, 5]
list.add(6)	// UnsupportedOperationException발생

   asList( ) 는 배열을  List 에 담아서 반환한다. 매개변수의 타입이 가변 인수라서 배열 생성 없이 저장할 요소들만 나열하는 것도 가능하다. 하지만  asList( ) 가 반환한  List 의 크기를 변경할 수 없어서 추가 또는 삭제가 불가능하다. 저장된 내용을 변경하는 것만 가능하다. 크기를 변경할 수 있는  List 가 필요하다면  List list = new ArrayList(Arrays.asList(1, 2, 3, 4, 5)); 라고 해야 한다.

 

 

  ■ parallelXXX( ), spliterator( ), stream( )

   parallel 로 시작하는 메서드들은 빠른 결과를 얻기 위해 여러 쓰레드가 작업을 나누어 처리하도록 한다.  spliterator( ) 는 여러 쓰레드가 처리할 수 있게 하나의 작업을 여러 작업으로 나누는  Spliterator 를 반환하며,  stream( ) 은 컬렉션을 스트림으로 변환한다.

 

 

 

 

 


Comparator와 Comparable

Comparable(java.lang 패키지) : 기본 정렬기준을 구현하는데 사용. 
Comparator(java.util 패키지) : 정렬기준을 따로 정렬하고 싶을 때 사용

 Comparator  Comparable 은 모두 인터페이스로 컬렉션을 정렬하는데 필요한 메서드를 정의하고 있다.  Comparable 을 구현하고 있는 클래스들은 같은 타입의 인스턴스끼리 서로 비교할 수 있는 클래스들( Wrapper 클래스와,  String ,  Date ,  File 등)이며 기본적으로 오름차순으로 정렬되도록 구현되어있다.  Comparable 을 구현한 클래스는 정렬이 가능하다는 것을 의미한다. 다른 기준으로 정렬되도록 하고 싶을 때  Comparator 를 구현해서 다른 정렬 기준을 제공할 수 있다.

 

 compare( )   compareTo( ) 는 선언 형태와 이름이 약간 다를 뿐 두 객체를 비교하는 메서드이다.  equals 는 모든 클래스가 가지고 있는 공통 메서드이지만  Comparator 를 구현하는 클래스는 오버 라이딩이 필요할 수도 있다는 것을 알리기 위해서 정의한 것일 뿐  compare(Object o1, Object o2) 만 구현하면 된다.

 

 

package Example;

import java.util.*;

public class Example {
	public static void main(String[] args) {
		String[] strArr = {"cat", "Dog", "lion", "tiger"};
		
		Arrays.sort(strArr);	// Comparable구현에 의한 정렬
		System.out.println("strArr = " + Arrays.toString(strArr));
		
		Arrays.sort(strArr, String.CASE_INSENSITIVE_ORDER);	// 대소문자 구분 X
		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;
	}
}

 

실행결과

위의 설명을 확인하는 예제이다.  Arraus.sor( ) 는 배열을 정렬할 때  Comparator 를 지정하지 않으면 저장하는 객체(주로  Comparable 을 구현한 클래스의 객체)에 구현된 내용에 따라 정렬된다. 기본 정렬에  -1 을 곱하면 역순으로 바뀐다는 것도 확인할 수 있다.

 

 

 

+ Recent posts