Dipa's document :: Dipa's document

안뇽하세요 ㅎ 이번시간에는 Map 컬렉션에 대해서 알아보도록 하겠습니다.

Map 컬렉션은 앞서 소개한 List 컬렉션 Set 컬렉션과는 또 다른 기능이 숨겨져 있습니다.

Map 컬렉션은 키(Key)와 값(Value)로 구성된 Entry객체를 저장하는 구조로서 하나의 키에 값이 저장이 되어 있습니다. 또한 Map 컬렉션의 특징으로는 키의 값이 중복저장이 안된다는 특징이 있습니다.

Map 컬렉션의 대표적인 클레스로는 HashMap, HashTable, TreeMap, Property가 있지만, TreeMap같은경우는 다음 포스팅떄 따로 TreeSet과 함께 포스팅을 하도록 하겠습니다.

* HashMap

HashMap의 특직으로는 앞서 포스팅한 HashSet의 특징과 같습니다. 다만 HashMap에서 equals()와 hashCode()를 Override를 할 경우에는 HashMap의 Key값을 가지고 비교를 하게 됩니다.

그렇다면 HashMap을 통한 소스코드를 보겠습니다.

public class HashMapExample {
	public static void main(String[] args) {
		Map<String,Integer> map = new HashMap<String,Integer>();
		
		map.put("지승훈", 90);
		map.put("지자바", 85);
		map.put("지가나", 70);
		map.put("지코인", 90);
		map.put("지이더", 80);
		map.put("지하라", 65);
		System.out.println("총 Entry 개수 : " + map.size());
		
		//1번쨰 방법
		Set<String> set = map.keySet();
		Iterator<String> iterator = set.iterator();
		while(iterator.hasNext()){
			String key = iterator.next();
			int value = map.get(key);
			System.out.println("key : " + key + ", value : " + value);
		}
		System.out.println();
		
		//2번쨰 방법
		Set<Map.Entry<String, Integer>> set2 = map.entrySet();
		Iterator<Map.Entry<String, Integer>> iterator2 = set2.iterator();
		while(iterator2.hasNext()){
			Map.Entry<String, Integer> entry = iterator2.next();
			String key = entry.getKey();
			int value = entry.getValue();
			System.out.println("key : " + key + ", value : " + value);
		}
	}
}

HashMap에서도 마찬가지로 객체를 가져와야 할경우에는 Iterator를 씁니다. 따라서 Iterator를 통하여 값을 처리를 하는 경우가 2가지가 있습니다. 첫번째로는 HashMap의 key값을 Set타입으로 받은 다음, 그 Set을 이용을 하여서 Iterator에 접목을 시키고 나머지는 Set에 저장되어 있는 Key값을 이용해 mapping을 하여 Key값에 대한 데이터를 처리를 합니다. 

두번째 방법으로는 첫번째 방법과 비슷한데, Map(Key,value) 전체 (즉, Entry)를 가져와서 Iterator를 처리를 하는 방법입니다.

* HashTable

HashTable 같은경우는 HashMap과 동일한 구조를 가지고 있습니다. 다만 차이점이 있다면 HashTable은 동기화(synchronized) 메소드로 구성되어 있기 떄문에, 멀티스레드 환경에서 데이터 처리를 안전하게 할수 있습니다.(Thread Safe)

 

Posted by SH후니
,

이번시간은 Set 컬렉션에 대해서 다뤄보도록 하겠습니다.ㅎㅎ

Set 컬렉션은 앞서 List 컬렉션과는 다르게 index로 관리되어지는 것이 아니라서 저장순서가 유지되어 지지 않습니다. 마치 하나의 주머니안에 데이터(객체)를 담는거라고 생각하시면 좋을꺼 같습니다 ㅎ

Set 컬렉션의 특징은 앞서 소개한 바로 순서가 보장되지 않고, 중복 저장이 되지 않는 것이 특징입니다.

따라서 Set 인터페이스의 메소드들은 기존의 List 인터페이스를 구현한 메소드들 중에서 인덱스와 관련된것은 뺴고 모두 동일하다고 생각하시면 됩니다.

Set 인터페이스를 구현한 대표적인 클레스로는 HashSet, TreeSet이 있습니다. 먼저 이 포스팅에서는 HashSet에서만 다루겠습니다. TreeSet같은경우에는 다음 포스팅에 나올 TreeMap과 함꼐 다루도록 하겠습니다. 

* HashSet

HashSet클레스 같은경우는 객체를 순서없이 저장을하고, 동일한 객체는 저장을 하지 않는 부분에 있어서 Set 인터페이스를 구현한 클레스 입니다.

HashSet 클레스는 객체를 저장을 하기전에 먼저 HashCode()를 통해서 해시코드를 얻어내고, 그 해시코드의 값을 가지고 동일한 객체가 저장이 되어 있는지 없는지에 대해서 조사를 하게 됩니다. 만약 동일한 해쉬코드가 나오면 다시 equals()를 통해서 한번더 점검을 한 후, 저장을 할지 말지에 대한 결정을 하게 됩니다.

HashCode()와, equals()메소드의 부분은 제 블로그에 나와 있으니 한번 참고를 해보시면 좋을꺼 같네요^^

그렇다면, 순서도 없이 저장된 객체를 어떻게 꺼내서 처리를 할 수 있을까요? 

결론부터 말하면 Set 인터페이스의 iterator() 라는 메소드 즉 반복자를 통해서 이용을 할 수 있습니다.  그럼 Iterrator 인터페이스를 보도록 하겠습니다.


public interface Iterator<E> { /** * Returns {@code true} if the iteration has more elements. * (In other words, returns {@code true} if {@link #next} would * return an element rather than throwing an exception.) * * @return {@code true} if the iteration has more elements */ boolean hasNext(); /** * Returns the next element in the iteration. * * @return the next element in the iteration * @throws NoSuchElementException if the iteration has no more elements */ E next(); /** * Removes from the underlying collection the last element returned * by this iterator (optional operation). This method can be called * only once per call to {@link #next}. The behavior of an iterator * is unspecified if the underlying collection is modified while the * iteration is in progress in any way other than by calling this * method. * * @implSpec * The default implementation throws an instance of * {@link UnsupportedOperationException} and performs no other action. * * @throws UnsupportedOperationException if the {@code remove} * operation is not supported by this iterator * * @throws IllegalStateException if the {@code next} method has not * yet been called, or the {@code remove} method has already * been called after the last call to the {@code next} * method */ default void remove() { throw new UnsupportedOperationException("remove"); } /** * Performs the given action for each remaining element until all elements * have been processed or the action throws an exception. Actions are * performed in the order of iteration, if that order is specified. * Exceptions thrown by the action are relayed to the caller. * * @implSpec * <p>The default implementation behaves as if: * <pre>{@code * while (hasNext()) * action.accept(next()); * }</pre> * * @param action The action to be performed for each element * @throws NullPointerException if the specified action is null * @since 1.8 */ default void forEachRemaining(Consumer<? super E> action) { Objects.requireNonNull(action); while (hasNext()) action.accept(next()); } }

이제 Iterator를 통해서 HashSet 클레스의 객체를 처리해보도록 하겠습니다.


public class Member {
	private String name;
	private int age;
	
	public Member(String name, int age){
		this.name = name;
		this.age = age;
	}
	
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public int getAge() {
		return age;
	}
	public void setAge(int age) {
		this.age = age;
	}
	
	@Override
	public int hashCode() {
		return name.hashCode() + age;
	}
	
	@Override
	public boolean equals(Object obj) {
		if(obj instanceof Member){
			Member member = (Member)obj;
			return (member.name.equals(this.name))&&(member.age==this.age);		
		}else{
			return false;
		}
	}
	
	@Override
	public String toString() {
		return name + " : " + age;
	}
}


public class HashSetExample {

	public static void main(String[] args) {
	
		Set<String> StringSet = new HashSet<String>();
		
		StringSet.add("지승훈");
		StringSet.add("홍길동");
		StringSet.add("지자바");
		StringSet.add("지후니");
			
		
		Iterator<String> iterator = StringSet.iterator();
		
		System.out.println("Set Size : " + StringSet.size());
		while(iterator.hasNext()){
			System.out.println(iterator.next().toString());
		}
		
		Set<Member> member = new HashSet<Member>();
		
		
		member.add(new Member("지승훈",27));
		member.add(new Member("홍길동",30));
		
		Iterator<Member> iterator2 = member.iterator();
		
		while(iterator2.hasNext()){
			System.out.println(iterator2.next().toString());
		}
	}

}


Posted by SH후니
,

오늘은 컬렉션 프레임워크 중에서 List 컬렉션에 대해서 알아보도록 하겠습니다.

List 컬렉션은 객체를 일렬로 늘어 놓은 구조로써, 객체를 인덱스로 관리를 하기 떄문에, 객체를 저장하면 자동으로 인덱스를 부여 하게 됩니다. 또한 리스트 컬렉션은 객체 자체를 저장하는 것이 아니라 객체의 참조 번지를 저장함으로써 힙영역에 객체를 가르키게 됩니다.

List 컬렉션의 특징으로는 앞서 컬렉션 프레임워크를 설명했을 때 처럼 순서를 유지하고 저장, 중복저장 가능하기 떄문에 같은 객체를 저장하게 되면 인덱스의 참조 번지는 같은 객체를 가르키게 되어 있고, null을 저장을 할 경우에는 인덱스에 있는 객체 참조 번지가 아무것도 가르키지 않게 됩니다.

* ArrayList

ArrayList 클레스에 객체를 저장을 하게 되면, 인덱스로 관리를 하게 됩니다. 일반 배열과 공통점은 인덱스로 관리한다는 점이지만, 배열과 ArrayList는 아주 큰 차이점이 있습니다.

바로 객체를 담을 크기가 유동적이라는 것입니다.!!

public class ArrayListExample {
   
	public static void main(String[] args) throws Exception {
		List<String> lists = new ArrayList<String>();
		
		
		//String 객체를 저장
		lists.add("java");
		lists.add("JDBC");
		lists.add("servlet/jsp");
		lists.add(2,"database");
		lists.add("ibaties");
		lists.set(4, "MyBatis");
		
		for(String list : lists){
			System.out.println(list.toString());
		}
		System.out.println();
		
		System.out.println("java라는 단어 있나요? " + lists.contains("java"));
		for(int i = 0; i<lists.size();i++){
			System.out.println(lists.get(i));
		}
		System.out.println();
		
		lists.remove(0);
		lists.remove("MyBatis");
		if(!lists.isEmpty()){
			lists.clear();
		}
		
		System.out.println("size : " + lists.size());
		
	}
}


ArrayList는 객체의 저장용량(capacity)을 default로는 10으로 설정이 되어 있다. 하지만 이 저장 용량을 초과하여 객체를 추가로 저장하게되면 자동적으로 값이 증가를 한다. 그렇다고 해서 다시 객체를 삭제를 한다고 해서 저장용량(capacity)이 줄어들지는 않는다.


public class ArrayListExample {
	 
    static int findCapacity(List<String> al) throws Exception {
        Field field = ArrayList.class.getDeclaredField("elementData");
        field.setAccessible(true);
        return ((Object[]) field.get(al)).length;
    }
   
	public static void main(String[] args) throws Exception {
		List<String> list = new ArrayList<String>();
		
		for(int i=0;i<100;i++){
			list.add(i+"");
			System.out.println("list_size : " + list.size() + ", list_ capacity : " + findCapacity(list));
		}
		
		System.out.println();
		
		for(int i=0;i<100;i++){
			list.remove(0);
			System.out.println("list_size : " + list.size() + ", list_ capacity : " + findCapacity(list));
		}
		
	}
}

* Vector

Vector클레스는 ArrayList 클레스의 구조와 비슷하지만 이 둘의 차이점은 멀티스레드의 환경에서 데이터를 처리를 하는지 입니다.. Vector클레스는 동기화된(synchronized)  메소드로 구성이 되어 있습니다. 따라서 멀티 스레드 환경에서 동시에 이 메소드를 접근을 할 수 없도록 구성 되어 있으며, 이를 스레드 안전 (Thread safe)라고 합니다


* LinkedList

linkedList 같은경우는 ArrayList와 사용 방법이 같습니다. 하지만 안의 내부구조가 다릅니다. ArrayList같은경우는 index에 의해서 관리가 되어 진다고 하면, LinkedList 같은경우는 인접해있는 노드를 연결해서 체인처럼 연결이 되어 있습니다. 따라서 중간의 데이터를 제거 하고싶다면 중간의 양쪽노드를 서로 이어주면 자동적으로 중간의 데이터는 없어지게 되는 것입니다.

예를 들어서 A->B->C 이렇게 연결이 되어 있을떄, B를 제거 하고싶으면 A에 연결되어있는 참조를 B가아닌 C로 이동을하여 A->C로 만들어주면 되겠죠? 


* ArrayList vs LinkedList

그렇다면 ArrayList와 LinkedList의 차이점은 무엇일까요? 둘은 쓰이는 곳이 다릅니다. 예를들어 수만개의 데이터가 있는데, 중간의 데이터를 추가하고 삭제하게되면 ArrayList값은 찾아서 데이터를 추가 삭제하고 그 다음칸에 있는 데이터는 한칸씩 뒤로 물러나게(index증가)됩니다. 그런데 이런 작업을 많이 하게되면 성능 저하의 원인이 되겠죠? 따라서 이런 작업이 많을 경우에는 LinkedList를 이용하는것이 좋습니다. 또한 검색/순차적으로 삭제&추가를 할 경우에는 ArrayList가 성능이 좋습니다.

정리 하자면, 

구분 

순차적으로 추가/삭제 

중간에 추가/삭제 

검색 

ArrayList 

빠르다

느리다 

빠르다 

 LinkedList

느리다 

빠르다 

느리다 



Posted by SH후니
,