ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • Collection Framework
    Java 2020. 11. 24. 08:36
    반응형

    Collection Famework 개요

    다수의 객체를 효율적으로 관리하기 위해 JAVA는 객체를 모아서 조작하는 기능들을 한데 모아 framework로 제공하는데 이를 Collection framewok 한다.

     

    배열을 사용하여 Collection framework 대채할 수 있지만 다음과 같은 단점이 있다.

    1. 배열은 초기화   크기가 고정되어 확장하기 어렵다. 
    2. 중간에 위치한 객체를 제거하는 경우 인덱스는 남아있으나 참조만 깨지게 되어 관리하기 어렵게 된다. (비어있는 배열 인덱스를 확인하는 성능비용이 발생된다.)

     

    Collection framework는 배열을 통해 객체를 관리할 때의 단점을 해결하고 보다 효율적인 기능을 제공한다. 객체들의 효율적인 추가, 삭제, 검색을위해 java.util 패키지에 Collection 관련된 interface class 정의해 놓았으며 이것이 바로 Collection framework이다.

     

    JAVA Collection 객체를 수집해서 저장하는 역할을 하고 framework 사용방법을 미리 정해놓은 library 말한다. 

     

     

     

     

    Collection Framework 구성

     

     

     

    List Collection

    List Collection 객체를 일렬로 늘어놓은 구조이다. 객채를 인덱스로 관리하기 때문에 객체를 저장하면 자동으로 인덱스가 부여되고 인덱스를 통해 객체를 조회, 검색, 삭제   있는 기능을 제공한다. List Collection 저장공간에 객체를 복사하여 저장하는 것이 아니라 객체의 참조주소를 저장한다. (인덱스0 1 각각 동일한 객체를 저장할 경우 인덱스01 서로 동일한 객체의 주소를 참조하게된다.) 참조주소를 저장하기에 참조가 없음을 표현하는 null 저장할  있다.

     

    List Collection(ArrayList, Vector, LinedList)에서 공통으로 사용되는 List Interface method 다음과 같다. List interface제네릭 타입이므로 구체적인 타입은 구현 객체를 생성할  결정된다.

     

     

     

    List Collection에서 참조하는 모든 객체를 Access 때는 for문을 사용한다.

    for(int i = 0; i < listCollection.size(); i++) {...}

     

    Index 사용할 일이 없다면 향상된 for문을 사용해도 무방하다.

    for(ObjectType object : listCollection) {...}

     

     

    1. ArrayList

    생성자를 통해 ArrayList 생성하면 10개의 객체를 참조할  있는 ArrayList 객체가 생성된다. 처음부터   용량의ArrayList 필요한 경우 매개변수에  크기를 지정하여 생성자를 호출한다.

     

    ArrayList 배열과는 달리 저장 용량을 초과하여 참조정보를 넣으려고 하면 자동으로 용량을 늘려 입력하게 된다.

     

    ArrayList 객체를 추가하면 인덱스 0부터 추가하게 되고 중간 인덱스를 제거하면 바로  인덱스 부터 마지막 인덱스까지 모두 앞으로 1 당겨진다. , 빈번한 참조정보의 삭제와 삽입이 필요한 경우에 대해 사용하기 어렵다. 이런 경우에는LinkedList 사용하는 것이 바람직하다.

     

     

    ArrayList 타입의 예

    List<String> ojbectName = new ArrayList<String>(10); //생성자 매개변수로 List 초기 size 지정가능. 지정하지 않으면 Default size = 10

     

    ArrayList 한번에 다수의 객체를 추가고자  때는 Arrays.asList( ) 사용하면 편하다.

    import java.util.Arrays;
    import java.util.List;
    
    public class ArraysAsListEX {
      public static void main(String[] args) {
        List<String> list = Arrays.asList(
            "Dave",
            "Mike",
            "Choi"
        );
    
        for(String name : list) {
            System.out.println(name);
        }
      }
    }

     

     

     

    2. Vector

    Vector Thread safe(동기화된 메소드로 구성되어  번에  Thread 접근이 가능 ) List Collection으로  구조는ArrayList 동일하다.

     

     

    Vector 타입 선언의 예 

    List<String> objectName = new Vector<String>();

     

     

    3. LinkedList

    LinedList 사용법은 ArrayList 동일. 내부구조는 인접한 저장소의 참조정보를 가지고있어 체인처럼 관리한다. 따라서특정 인덱스에 해당하는 저장소를 제거하면 제거된 저장소에 인접한  저장소의 링크만 변경된다. 객체의 삽입과 삭제가 빈번하게 발생하는 경우 ArrayList보다 좋은 성능을 기대할  있다. 다만 참조의 추가, 삭제가 크게 없는 경우는ArrayList 사용하는 것이 조회 속도를 비약적으로 높일  있다.( 280 차이)

     

    LinkedList 타입 선언의 예

    List<String> objectName = new LinkedList<String>();

     

     

     

     

    Set Collection

    저장순서가 유지되지 않고 객체를 중복해서 저장할  없으며 null또한 하나의 요소로 인식하여 한번만 저장할  있는컬렉션이다.

     

    Set Collection method 다음과 같다.

     

     

    Set Collection Set 포함된 모든 객체들(집합요소) 한번씩 가지고 오는 Iterator 제공한다. Iterator Iterator interface 구현한 객체이며 iterator( ) 메서드를 호출하여 얻을  있다.

    Set<String> set = new Set<String>();
    set.add("1");
    set.add("2");
    set.add("3");
    Iterator<String> iterator = set.iterator();

     

     

     

    iterator 통해 Set collection 객체참조를 가져오기 전에 hasNext( ) 메서드로 가져올 참조가 있는지 먼저 확인한 후에next( ) 메서드로 가져오는 것이 좋다.

    Set<String> set = new Set<String>();
    Iterator<String> iterator = set.iterator();
    while(iterator.hasNext()) {
    	String str = iterator.next();
    }
    

     

     

     

    Iterator 사용하지 않고 Set Collection 대해 향상된 for문을 사용하여 Set Collection 모든 객체참조를 순회할  있다.

    Set<String> set = new Set<String>();
    for(String str : set) {
    	//각 집합요소에 대해 필요한 작업을 한다.
    }

     

     

    1. HashSet

    객체의 상태가 동일함을 확인하기 위해서는  가지 확인을 거쳐야 한다. 우선 hash value 같은지 확인하고 두번째로 실제 field 값들이 동일한지 확인한다.

    hash 단방향 암호화 기법중 하나이다. hash 통해 value(평문) 고정길이로 암호화된 문자열로 변경한다.   원본데이터는 key이고 암호화된 문자열이 hash value이다. 단순히 실제 field 값으 비교만으로도 객체들의 상태가 동일함을 확인할  있는데  filed 비교에 앞서 hash value 확인하는 것일까?

    hash 사용하는 이유는 데이터를 분산된 공간에 저장하고  공간을 인덱싱 하여 데이터를 조회할  hash value 속하는 범위의 index 해당하는 데이터들만 조회 하도록 하는 것으로 조회속도를 높이기 위해서이다.

    (ex)

    0~99 까지의 데이터가 있다고   55 조회한다고 하면 0부터 55 나올 때까지 55 비교연산이 필요하다.

    조회 속도를 개선하기 위해 다음과 같이 hashing 이용한다.

    1. value 고유의 hash값으로 변환한다.
    2. hash값들을 나눠담을 indexing 영역을 만든다. (int hashArea[10] 같이...)
    3. index 개수로 hash값을 mod연산하여 결과에 해당하는 index hash값을 담는다.
    4. 조회할  hash값을 mod연산한 결과에 해당하는 index 데이터들만 비교하는 것으로 조회속도를 높일 있다.

     

    따라서 HashSet 저장되는 객체참조 요소들의 중복여부를 확인하기 위해서는 객체를 생성하기 위한 Class boolean equals(Object o) 메서드와 int hashCode( ) 메서드를 Override해야 한다.

     

     

     

     

    Map Collection

    Map Collection 키값쌍(Key - Value)으로 구성된 Entry객체를 저장하는 구조를 가지고 있다. 키와 값은 모두 객체이다. 값은 중복으로 저장할  있지만 키는 중복저장이 불가하다. 기존에 저장한 키와 동일한 값으로 저장하면 값을 Update한다.

     

    Map collection에서 공통으로 사용할  있는 Map Interface method 목록은 다음과 같다.

     

     

    Map collection 모든 요소에 대해 순회하는 방법

    keySet( ) 메서드로 모든 키를 Set 컬렉션으로 얻은 다음, 반복자를 통해 키를 하나씩 얻고 get( )메소드를 통해값을 얻는 방법

    Map<K, V> map = ...;
    Set<K> keySet = map.keySet( );
    Iterator<K> keyIterator = keySet.iterator( );
    while(keyIterator.hasNext( )) {
      K key = keyIterator.next( );
      V value = map.get(key);
    }

     

     

    entrySet( ) 메서드로 모든 Mapy.Entry객체를 Set 컬렉션으로 얻은 다음, 반복자를 통해 Map.Entry 객체를 하나씩 접근하고, 접근한 Map.Entry객체에 대해 getKey( ) getValue( ) 메서드로 각각 키와 값을 얻는 방법

    Map<String, String> map = new HashMap<>();	// ①
    Set<Map.Entry<String, String>> entrySet = map.entrySet();	// ②
    Iterator<Map.Entry<String, String>> entryIterator = entrySet.iterator();	// ③
    while(entryIterator.hasNext()) {	// ④
    	Map.Entry<String, String> entry = entryIterator.next();	// ⑤
    	K key = entry.getKey();	// ⑥
    	V value = entry.getValue();	// ⑦
    }
    

    ① HashMap<Key, Value> 타입의 key와 value는 통상적으로 String타입을 사용하는데 이는 동일 객체를 확인하기 위한 hashCode()와 equals()가 미리 정의되어 있기 때문이다.

    ② Map타입 객체의 entrySet() 메서드를 사용하여 객체 안에 있는 entry(등록된 데이터들)를 Set<Map.Entry<String, String>> 타입의 객체(entrySet)에 담는다.

    Set<Map.Entry<String, String>> 타입은 Set 타입 객체이므로 iterator() 메서드를 사용하여 Set 타입의 각 요소들에 접근하기 위한 Iterator 타입의 객체를 얻을 수 있다.

    ④  이터레이터 타입의 hasNext() 메서드를 통해 다음 접근할 요소가 있는지 확인하면 반복문을 실행한다. 접근할 요소가 있으면 true가 반환되어 반복문 내부가 실행되며 없으면 false가 반환되어 반복문이 종료되는 구조이다.

    ⑤ Iterator 타입 객체의 next() 메서드를 사용하여 hasNext()를 통해 있는지 확인했던 Map.Entry<Key, Value> 타입의 객체에 실제로 접근한다.

    ⑤에서 접근한 Map.Entry<Key, Value> 타입 객체의 getKey() 메서드를 사용하여 Map에 등록된 key 데이터를 받아온다.

    ⑦ ⑤에서 접근한 Map.Entry<Key, Value> 타입 객체의 getValue() 메서드를 사용하여 Map에 등록된 value 데이터를 받아온다.

     

     

     

    Set 컬렉션과 향상된 for문을 조합하여 Map 컬렉션 요소에 접근하능 방법

    Map<String, String> map = new HashMap<>();
    
    map.put("3", "mike");
    map.put("2", "jane");
    map.put("4", "dave");
    map.put("1", "john");
    
    for(Map.Entry<String, String> entry : map.entrySet()) {	// ①
        System.out.println(entry.getKey() + ", " + entry.getValue());	// ②
    }

    ① Map.entrySet() 메서드로 Map 타입 객체의 entry set 객체를 생성하고 향상된 for문을 통해 entry set의 각 요소에 접근한다.

    ② 각 entry set 요소별로 getKey()와 getValue() 메서드를 사용하여 key와 value를 각각 얻어낼 수 있다.

     

     

     

     

    1. HashMap

    HashMap key 사용할 객체는 hashCode( ) equals( ) 메서드를 override하여 동등 객체가  조건을 정해야 한다.

     

    key 타입은 주로 String 사용하는데, String 문자열이 같은 경우 동등 객체로 판단하도록 hasCode( ) equals( ) 이미 override되어 있기 때문이다.

     

    HashMap 생성하기 위해서는 key value 타입을 파라메터로 주고 기본 생성자를 호출하면 된다.

    Map<String, String> map = new HashMap<String, String>( );

     

    key value 타입은 클래스와 인터페이스 타입만 사용할  있다. (기본 타입은 사용불가)

     

     

     

    2. HashTable

    HashTable HashMap 동일한 내부구조를 가지고 있으므로 key 사용할 객체는 hashCode( ) eqauls( )  override하여객체 동등 조건을 정해야 한다.

     

    HashTable HashMap과는 다르게 동기화된 메서드로 구성되어 있기 때문에 Thread safe하다.

     

    HashTable 생성하기 위한 구문은 다음과 같다.

    Map<Stirng, String> table = new HashTable<String, String>( );

     

     

     

    3. Properties

    Properties HashTable 하위 클래스이다. 따라서 HashTable 모든 특징을 그대로 가지고 있다. , 차이점은 HashTable 경우 key value 타입으로 모든 클래스와 인터페이스 타입으로 지정할  있으나 Properties 경우 key value 모두String으로만 지정 가능하다는 것이다.

     

    Properties 어플리케이션의 옵션 정보, 데이터베이스 연결정보, 국제화(다국어) 정보 등이 저장된 *.properties 파일을 읽을  주로 사용한다.

     

    프로퍼티 파일은 key value = 기호로 연결되어 있는 텍스트 파일로 ISO 8859-1 문자셋으로 저장된다. ISO 8859-1 문자셋으로 표현할  없는 한글은 유니코드로 변환되어 저장된다. 유니코드 변환을 자동으로 진행해주는 IDE 사용하지않을 경우 JDK 설치 경로의 \bin\native2ascii.exe 사용하여 ISO-8859-1 파일을 얻으면 된다.

    • native2ascii.exe OriginFileName.properties DestFileName.properties

     

     

    프로퍼티 파일을 읽어들이기 위한 순서

    1. Properties 객체를 생성
    2. FileReader 객체를 매개값으로 하여 load( ) 메서드를 호출한다.
    Properties properties = new Properties( );
    properties.load(new FileReader(/*프로퍼티 파일이 위치한 경로를 문자열 형태로 입력*/));

     

    프로퍼티 파일은 일반적으로 *.class 파일과 함께 저장된다. *.class 파일을 기준으로 상대경로를 이용하여 프로퍼티 파일의 경로를 얻을  있다. 프로퍼티 파일의 절대경로는 다음과 같이 얻는다.

    1. Class getResource( ) 메소드를 호출하여 매개변수로 지정된 파일의 상대 경로를 URL 객체로 리턴

    2. URL 객체의 getPath( ) 메서드를 호출하여 프로퍼티 파일의 절대경로를 얻는다.

    String path = 클래스명.class.getResouce("database.properties").getPath();

    3. 경로에 한글이 포함된 경우 utf-8 디코딩하여 복원해준다.

    path = URLDecoder.decode(path, "utf-8");

     

    4. load( ) 메서드에 매개값으로 프로퍼티 파일 경로(path) 지정하여 파일을 읽어들인다.

    String path1 = A.class.getResource("database.properties").getPath();
    String path2 = A.class.getResource("config/database.properties").getPath();	// ①
    
    Properties properties = new Properties();
    properties.load(path1);

    만약 다른 패키지에 프로퍼티 파일이 있을 경우 경로 구분자 "/" 사용한다. 

     

    Propertie 객체에서 특정 key value 확인

    Propertie 객체의 getProperty( ) 메소드에 매개값으로 key 전달하여 value 확인한다. Properties Map 컬렉션이므로 get( ) 메서드로 값을 얻을  있지만 get( ) 메서드의 경우 리턴 값이 Object이므로 String 타입으로 강제 타입변환이 필요하기 때문에 일반적으로 getProperty( ) 메서드를 사용하여 value 확인한다.

    Sting value = properties.getProperty("key");

    'Java' 카테고리의 다른 글

    문자열 뒤집기 예제  (0) 2020.12.10
    형변환 (type casting)  (0) 2020.12.04
    라이브러리를 사용한 배열 정렬  (0) 2020.11.30
    Map의 정렬  (0) 2020.11.28
    콘솔 입력  (0) 2020.10.08

    댓글

Designed by Tistory.