티스토리 뷰

Developer

[JAVA] Collectoion 활용하기

rocksea 2016. 1. 5. 21:27

Java Collectoion 활용하는 방법.

Java에는 동적할당이 가능한 자료구조 

(ArrayListLinkedListVectorStackHashSetHashMapHashtable)

들이 존재하며, 통합된 구조의 Collection Framework을 호출하여 사용하도록 설계되었으며, Collection Framework는 통합된 인터페이스를 통해 collection의 element에 대한 조회, 저장등을 제공한다.

Collection Framework 패키지에 포함된 내용들이다.

1. 인터페이스

2. 구현클래스

3. 알고리즘

C++의 Standard Template Library와 유사하다.

JDK1.2이전에 Vector나 Hashtable의 인터페이스의 경우, 인터페이스가 일치하지 않은 비통합된 방식으로 설계 되었다. 그리하여 JDK1.2에서 Collection Framework를 도입하여 기존의 Vector, Hashtable을 Collection Framework에 통합하였다.

JDK 1.5에서는 Generic(다양한 자료형 전달 방식)과 이와 관련된 기능 (예: auto-boxing, unboxing, 개선된 for loop문)이 소개되었고, Collection Framework는 Generic을 지원하기 위해 개선되어 최대한의 특장점을 살렸다.


1. Generic 사용 예제.

[그림 1] List Interface 및 Implementaion 객체 구성


JDK 1.5 이전의 ArrayList 사용법.

import java.util.List;
import java.util.ArrayList;
import java.util.Iterator;
 
public class ArrayListPreJDK15Test {
   public static void main(String[] args) {
      List lst = new ArrayList();  // A List contains instances of Object. Upcast ArrayList to List
      lst.add("alpha");            // add() takes Object. String upcast to Object implicitly
      lst.add("beta");
      lst.add("charlie");
      System.out.println(lst);     // [alpha, beta, charlie]
 
      // Get a "iterator" instance from List to iterate thru all the elements of the List
      Iterator iter = lst.iterator();
      while (iter.hasNext()) {      // any more element
         // Retrieve the next element, explicitly downcast from Object back to String
         String str = (String)iter.next();
         System.out.println(str);
      }
   }
}

일일이 다운캐스팅을 명시적으로 표시해 줘야한다.


JDK 1.5 이후의 ArrayList 사용법.

// Post-JDK 1.5 with Generics
import java.util.List;
import java.util.ArrayList;
import java.util.Iterator;
 
public class ArrayListPostJDK15Test {
   public static void main(String[] args) {
      List<String> lst = new ArrayList<String>();  // Inform compiler about the type
      lst.add("alpha");         // compiler checks if argument's type is String
      lst.add("beta");
      lst.add("charlie");
      System.out.println(lst);  // [alpha, beta, charlie]
 
      Iterator<String> iter = lst.iterator();   // Iterator of Strings
      while (iter.hasNext()) {
         String str = iter.next();  // compiler inserts downcast operator
         System.out.println(str);
      }
 
//      lst.add(new Integer(1234));   // ERROR: compiler can detect wrong type
//      Integer intObj = lst.get(0);  // ERROR: compiler can detect wrong type
 
      // Enhanced for-loop (JDK 1.5)
      for (String str : lst) {
         System.out.println(str);
      }
   }
}

Generic을 지원으로 Compiler가 다운캐스팅을 삽입하여, Runtime시 발생하는 ClassCastException을 예방 할 수 있다. 

또한 새로운 구조의 for-loop로 loop문의 사용성을 높였다.


2. Auto-Boxing & Auto-Unboxing

정수,실수의 원시 자료형에 대한 Wrapping된 객체에대해 JDK1.5이전에는 직접 Wrapping, UnWrapping을 하여 사용하였다면, JDK1.5 이후에는 Compiler에서 자동으로 Wrapping, UnWrapping을 수행한다. 이를 JDK1.5에서 Boxing, UnBoxing이라고 한다.

[그림 2] 원시 자료형 Wrapper 객체


JDK 1.5 이전의 Boxing

 
public class BoxingPreJDK15Test {
   public static void main(String[] args) {
      // Pre-JDK 1.5
      Integer intObj = new Integer(5566);    // wrap int to Integer
      int i = intObj.intValue();             // unwrap Integer to int

      Double doubleObj = new Double(55.66);  // wrap double to Double
      double d = doubleObj.doubleValue();    // unwrap Double to double
   }
}

직접 수동으로 객체를 선언하여 Wrapping해야 하고, 값을 불러올때에도 메서드를 직접 호출하여 UnWrapping한다.


JDK 1.5 이후의 Boxing

 
public class BoxingPreJDK15Test {
   public static void main(String[] args) {
     // JDK 1.5
     Integer intObj = 5566;    // autobox from int to Integer
     int i = intObj;           // auto-unbox from Integer to int

     Double doubleObj = 55.66; // autoboxing from double to Double
     double d = doubleObj;     // atuo-unbox from Double to double
   }
}

객체에 직접 값을 넣을 수 있다. 이를 Auto-Boxing 이라고 하며, 그 값을 다시 원시 자료형에 넣을때 원시 자료형을 Auto-Unboxing하여 다시 원시 자료형에 담을 수 있다.


3. Collection Interfaces

인터페이스에 대한 hierarchy관계를 이해하고 사용예제를 통해 각 인터페이스에 대한 특성을 확인해 보도록 한다.

[그림 3] Collection Interface 구성도


기본적으로 Collection의 경우 연속된 순서의 선형 자료형을 구현한 인터페이스이며, MAP은 Key, Value를 다루는 자료형을 구현한 인터페이스 이다. 기존에 구현된 Vector와 Hashtable의 경우, Synchronized를 지원하도록 설계되었기 때문에 다중 스레드 접근 시 병목현상을 유발할 수 있기 때문에 유의해서 사용하도록 한다.


3.1. 반복 Interface Iterator

 
List<String> lst = new ArrayList<String>();
lst.add("alpha");
lst.add("beta");
lst.add("charlie");
 
// Retrieve the Iterator associated with this List via the iterator() method
Iterator<String> iter = lst.iterator();
// Transverse thru this List via the Iterator
while (iter.hasNext()) {
   // Retrieve each element and process
   String str = iter.next();
   System.out.println(str);
}
 

선형 자료구조 객체 조회 시 사용되는 인터페이스이다. next()를 이용하여 다음 Element로 포인터를 이동하며 조회한다.


3.2. 개선된 For Loop (JDK1.5)

 
for ( type item : Collection ) {
   System.out.println(item);
}
 

마치 Foreach와 같이 각각의 Eelement를 item 변수에 대입한다.


3.3. Collection<E> Interface

import java.util.*;

public class CollectionTest {
   public static void main(String[] args) {
      Collection<String> a;
      List<String> b = new ArrayList<String>();
      List<String> c = new ArrayList<String>();
      a=b;

      // add
      a.add("Banana");
      a.add("Apple");
      a.add("Water Melon");
      for(String item : a){
        System.out.println(item);
      }

      // isEmpty
      System.out.println("isEmpty : " + a.isEmpty());

      // contains
      System.out.println("contains : " + a.contains("Apple"));
      System.out.println("contains : " + a.contains("Apple!"));

      // remove
      System.out.println("remove : " + a.remove("Apple"));
      System.out.println("list after remove : " + a);

      // removeAll
      System.out.println("removeAll : " + a.removeAll(a));
      System.out.println("list after removeAll : " + a);

      // retainAll
      a.add("Banana");
      a.add("Apple");
      a.add("Water Melon");

      c.add("Banana");
      c.add("Apple");

      System.out.println("retainAll : " + a.retainAll(c));
      System.out.println("list after retainAll : " + a);
   }
}


Collection 객체를 Upcasting하여 공통의 인터페이스로 자료에 대한 입력,출력,삭제가 가능하다.

또한 Collections를 이용하면 Synchronized 자료구조를 처리 할 수 있다. 아래의 예제를 통해 확인할 수 있다.


3.4. Collections Synchronized 

import java.util.*;

public class SynchronizedCollectionTest {
   public static void main(String[] args) {
       // create vector object
       List<String> list = new ArrayList<String>();

       // populate the list
       list.add("1");
       list.add("2");
       list.add("3");
       list.add("4");
       list.add("5");

       // create a synchronized list
       List<String> synlist = Collections.synchronizedList(list);
       System.out.println("list :"+synlist);
   }
}



3.5. Collections를 이용한 Sorting & Searching

 
import java.util.Arrays;
import java.util.List;
import java.util.ArrayList;
import java.util.Collections;

public class CollectionSortTest {
   public static void main(String[] args) {
      // Sort and search an "array" of Strings
      String[] array = {"Hello", "hello", "Hi", "HI"};

      // Use the Comparable defined in the String class
      Arrays.sort(array);
      System.out.println(Arrays.toString(array));  // [HI, Hello, Hi, hello]

      // Try binary search - the array must be sorted
      System.out.println(Arrays.binarySearch(array, "Hello")); // 1
      System.out.println(Arrays.binarySearch(array, "HELLO")); // -1 (insertion at index 0)

      // Sort and search a "List" of Integers
      List<Integer> lst = new ArrayList<Integer>();
      lst.add(22);  // auto-box
      lst.add(11);
      lst.add(44);
      lst.add(33);
      Collections.sort(lst);    // Use the Comparable of Integer class
      System.out.println(lst);  // [11, 22, 33, 44]
      System.out.println(Collections.binarySearch(lst, 22)); // 1
      System.out.println(Collections.binarySearch(lst, 35)); // -4 (insertion at index 3)
   }
}

간단한 정렬 및 검색(이진검색)등의 알고리즘이 구현되어 있으므로 간편하게 정렬 및 검색 등을 사용할 수 있다. String의 경우 유니코드 값을 비교하여(대문자가 소문자보다 작다) 정렬된다.

Java내의 구현되어있는 다양한 자료구조 및 알고리즘을 이해하고, Collection을 잘 활용하면 상당한 생산성과 성능 향상의 이득을 볼 수 있을 것이다. 특히 설계 시 동기화를 구현해놓은 Vector나 Hashmap, StringBuffer등의 객체사용 시 동기화로 인한 병목이 발생하므로 이점을 항상 유의해야한다.


이미지 출처 및 참조 URL :

https://www3.ntu.edu.sg/home/ehchua/programming/java/J5c_Collection.html

댓글