자바

컬렉션 프레임워크

tttck88 2019. 4. 15. 03:21

프레임워크는 쉽게 말해 인터페이스와 클래스의 모임

 

배열의 문제점

- 저장할 수 있는 객체 수가 배열을 생성할 때 결정 : 불특정 다수의 객체를 저장하기에는 문제

- 객체를 삭제했을 때 해당 인덱스가 비워진 상태로 있음

 

컬렉션 프레임워크

- 객체를 효율적으로 추가, 삭제, 검색할 수 있도록 제공되는 컬렉션 라이브러리

- java.util 패키지에 포함

- 인터페이스를 통해서 정형화된 방법으로 다양한 컬렉션 클래스를 이용

 

List

특징

- 인덱스로 관리

- 중복해서 객체 저장 가능

 

list.remove(0); 인덱스로 삭제

list.remove("한"); 객체로 삭제

 

ArrayList

저장용량 

- 초기10, 초기용량 지정가능, 저장 용량을 초과한 객체들이 들어오면 자동적으로 늘어난다.

객체제거

- 바로 뒤 인덱스부터 마지막 인덱스까지 모두 앞으로 1씩 당겨진다.

 

고정된 객체들로 구성된 List 생성

List<T> list = ArrayList.asList(T ... a);

List<String> list1 = ArrayList.asList("홍길동", "신용권");
for(String name: list1) {
	sysout(name);
}

List<Integer> list2 = ArrayList.asList("1", "2");
for(int value: list2) {
	sysout(value);
}

Vector

특징

- Vector는 스레드 동기화가 되어 있기 때문에

복수의 스레드가 동시에 Vector에 접근해서 객체를 추가, 삭제하더라도 스레드에 안전하다.

ArrayList는 싱글스레드에서 Vector는 멀티스레드에서 사용하도록 하자

 

LinkedList

특징

- 인접 참조를 링크해서 체인처럼 관리

- 특정 인덱스에서 객체를 제거하거나 추가하게 되면 바로 앞뒤 링크만 변경

- 빈번한 객체 삭제와 십입이 일어나는 곳에서는 ArrayList보다 좋은 성능을 발휘

 

Set

특징

- 수학의 집합에 비유될 수 있다.

- 저장 순서가 유지되지 않는다.

- 객체를 중복해서 저장할 수 없다

- 하나의 null만 저장할 수 있다.

 

Set컬렉션은 인덱스로 객체를 검색해서 가져오는 매소드가 없다. 대신, 전체 객체를 대상으로 한번씩 반복해서 가져오는 반복자(iterator)를 제공한다.

Set<String> set = ...;
Iterator<String> iterator = set.iterator();
while(iterator.hasNext()) {
	//String객체 하나를 가져옴
    String str = iterator.next();
}

Set<String> set = ...;
for(String str : set) {
}

 

HashSet

특징

- 동일객체뿐만 아니라 동등객체도 중복 저장하지 않는다 : hashCode()리턴값과 equals()리턴값을 확인

 

Map

특징

- 키와 값으로 구성된 Map.Entry 객체를 저장하는 구조

- 키와 값은 모두 객체

- 키는 중복될 수 없지만 값은 중복 저장가능

Map<String,Integer> map = ~;
map.put("홍길동",30);
int score = map.get("홍길동");
map.remove("홍길동");

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);
}

Set<Map.Entry<K,V>> entrySet = map.entrySet();
Iterator<<Map.Entry<K,V>> entryIterator = entrySet.iterator();
while(entryIterator.hasNext()) {
	Map.Entry<K,V> entry = entryIterator.next();
    K key = entry.getKey();
    V value = entry.getValue();
}

HashTable

- 스레드 동기화가 되어있기에 복수의 스레드가 동시에 접근해서 객체를 추가,삭제를 하여도 스레드에 안전하다.

 

Properties

특징

- 키와 값을 String 타입으로 제한한 Map 컬렉션이다.

- Properties는 프로퍼티 파일을 읽어 들일 때 주로 사용한다.

 

프로퍼티파일

- 옵션정보, 데이터베이스연결정보, 국제화정보를 기록한 텍스트 파일로 활용

- 애플리케이션에서 주로 변경이 잦은 문자열을 저장해서 유지 보수를 편리하게 만들어 줌

 

[databas.properties] 키 = 값으로 구성된 프라퍼티

driver = oracle.jdbc.OracleDriver

url = jdbc:oracle:thin:@localhost:1521:orcl

username = scott

password = tiger

 

Properties 객체 생성

파일 시스템 경로를 이용
Properties properties = new Properties();
Properties.load(new FileReader("C:/~/database.properties"));

ClassPath를 이용
String path = 클래스.getResource("database.properties").getPath();
//String path = PropertiesExample.class.getResource("datavase.properties").getPath();
//String path = A.getResource("cofig/database.properties").getPath();
path = URLDecoder.decode(path, "utf-8") 경로에 한글이 있을 경우 한글을 복원
Properties properties = new Properties();
Properties.load(new FileReader(path);

값 읽기
String value = properties.getProperty("key");
public class PropertiesExample {

	public static void main(String[] args) throws Exception {
		Properties properties = new Properties();
		String path = PropertiesExample.class.getResource("datavase.properties").getPath();
		path = URLDecoder.decode(path, "utf-8");
		properties.load(new FileReader(path));
		
		String driver = properties.getProperty("driver");
		String url = properties.getProperty("url");
		String username = properties.getProperty("username");
		String password = properties.getProperty("password");
	}
}

 

검색 기능을 강화시킨 컬렉션

TreeSet,TreeMap 이진트리 사용하기 때문에 검색 속도 향상

 

이진트리구조

- 부모 노드와 자식 노드로 구성

- 왼쪽 자식 노드 : 부모 보다 적은 값 / 오른쪽 자식 노드 : 부모 보다 큰 값

 

정렬이 쉬움

- 올림차순 : 왼쪽 부모 오른쪽노드

- 내림차순 : 오른쪽 부모 왼쪽노드

 

범위검색이 쉬움

 

TreeSet

특징

- 이진트리를 기반으로한 Set컬렉션

- 왼쪽과 오른쪽 자식노드를 참조하기 위한 두개의 변수로 구성

주요메소드

- 특정 객체를 찾는 메소드 : first(), last(), lower(), higher(), ...

- 정렬 메소드 : descendingIterator(), descendingSet()

- 범위 검색 메소드 : headSet(), tailSet(), subSet()

 

public class TreeSetExample {

	public static void main(String[] args) throws Exception {
		TreeSet<Integer> scores = new TreeSet<>();
		scores.add(87);
		scores.add(98);
		scores.add(75);
		scores.add(95);
		scores.add(80);
		
		Integer score = null;
		
		score = scores.first(); //가장 왼쪽에 있는 값
		score = scores.last(); //가장 오른쪽에 있는 값
		score = scores.lower(95); //95 아래에 있는 값
		score = scores.higher(95); //95 위에 있는 값
		score = scores.floor(95); //95가 있으면 해당 값 리턴 없으면 아래 값 리턴
		score = scores.ceiling(85); //85가 있으면 해당 값 리턴 없으면 위에 값 리턴
		
		while(!scores.isEmpty()) {
			score = scores.pollFirst(); //이진트리에서 제일 왼쪽에 있는 값부터 빼내서 제거
//			score = scores.pollLast(); //이진트리에서 제일 오른쪽에 있는 값부터 빼내서 제거
		}
		
		Iterator<Integer> iterator = scores.iterator();
		while(iterator.hasNext()) {
			int s = iterator.next();
			iterator.remove();
		}
	}
}
public class TreeSetExample {

	public static void main(String[] args) throws Exception {
		TreeSet<Integer> scores = new TreeSet<>();
		scores.add(87);
		scores.add(98);
		scores.add(75);
		scores.add(95);
		scores.add(80);
		
		NavigableSet<Integer> descendingSet = scores.descendingSet(); //내림차순으로 정렬 된 Set을 반환
		for(Integer score : descendingSet) {
			System.out.println(score + " ");
		}
		System.out.println();
		
		NavigableSet<Integer> ascendingSet = descendingSet.descendingSet(); //다시 하면 오름차순으로 변함
		for(Integer score : ascendingSet) {
			System.out.println(score + " ");
		}
		System.out.println();
	}
}
public class TreeSetExample {

	public static void main(String[] args) throws Exception {
		TreeSet<String> treeSet = new TreeSet<>();
		treeSet.add("apple");
		treeSet.add("forever");
		treeSet.add("description");
		treeSet.add("ever");
		treeSet.add("zoo");
		treeSet.add("base");
		treeSet.add("guess");
		treeSet.add("cherry");
		//알파벳에 순서에 따름
		
		System.out.println("[c~f 사이의 단어 검색");
		NavigableSet<String> rangeSet = treeSet.subSet("c", true, "f", true);
		for(String word : rangeSet) {
			System.out.println(word);
		}
	}
}

TreeMap

특징

- 이진 트리를 기반으로 한 Map 컬렉션

- 키와 값이 저장된 Map.Entry를 저장

- 왼쪽과 오른쪽 자식노드를 참조하기 위한 두개의 변수로 구성

- 키로 대소 비교

public class TreeMapExample {

	public static void main(String[] args) throws Exception {
		TreeMap<Integer,String> scores = new TreeMap<>();
		scores.put(87, "홍길동");
		scores.put(87, "이동수");
		scores.put(87, "박길순");
		scores.put(87, "신용권");
		scores.put(87, "김자바");
		
		Map.Entry<Integer, String> entry = null;
		
		entry = scores.firstEntry();
		System.out.println(entry.getKey() + entry.getValue());
		entry = scores.lastEntry();
		entry = scores.lowerEntry(95);
		entry = scores.higherEntry(95);
		entry = scores.floorEntry(95);
		entry = scores.ceilingEntry(95);
		
		while(!scores.isEmpty()) {
			entry = scores.pollFirstEntry();
		}
	}
}
public class TreeMapExample {

	public static void main(String[] args) throws Exception {
		TreeMap<Integer,String> scores = new TreeMap<>();
		scores.put(87, "홍길동");
		scores.put(87, "이동수");
		scores.put(87, "박길순");
		scores.put(87, "신용권");
		scores.put(87, "김자바");
		
		NavigableMap<Integer, String> descendingMap = scores.descendingMap();
		Set<Map.Entry<Integer, String>> descendingEntrySet = descendingMap.entrySet();
		for(Map.Entry<Integer, String> entry : descendingEntrySet) {
			System.out.println(entry.getKey() + entry.getValue());
		}
	}
}

 

Comparable과 Comparator

TreeSet과 TreeMpa의 자동 정렬

- TreeSet의 객체와 TreeMap의 키는 저장과 동시에 자동 오름차순으로 정렬

- 숫자타입일 경우에는 값으로 정렬

- 문자열 타입일 경우에는 유니코드로 정렬

- TreeSet과 TreeMap은 정렬을 위해 java.lang.Comparable을 구현한 객체를 요구

Integer.Double,String은 모두 Comparable 인터페이스를 구현한 클래스

Comparable을 구현하고 있지 않을 경우에는 저장하는 순간 ClassCastException이 발생

 

사용자정의 객체를 정렬하고 싶을 경우

방법1. 사용자 정의 클래스가 Comparable을 구현

public class Person implements Comparable<Person>  {
	public String name;
	public int age;
	
	public Person(String name, int age) {
		this.name = name;
		this.age = age;
	}

	@Override
	public int compareTo(Person o) {
		if(age<o.age) return -1;
		else if(age == o.age) return 0;
		else return 1;
	}
}

class ComparableExample {

	public static void main(String[] args) {
		TreeSet<Person> treeSet = new TreeSet<>();
		
		treeSet.add(new Person("홍길동", 45));
		treeSet.add(new Person("감자바", 25));
		treeSet.add(new Person("박지원", 31));
		
		Iterator<Person> iterator = treeSet.iterator();
		while(iterator.hasNext()) {
			Person person = iterator.next();
		}
	}
}

 

방법2. TreeSet, TreeMap 생성시 Comparator 구현 객체 제공

public class ComparatorExample {

	public static void main(String[] args) {
		TreeSet<Fruit> treeSet = new TreeSet<Fruit>(new DescendingComparator());
		
		treeSet.add(new Fruit("포도", 3000));
		treeSet.add(new Fruit("수박", 10000));
		treeSet.add(new Fruit("딸기", 6000));
		
		Iterator<Fruit> iterator = treeSet.iterator();
		while(iterator.hasNext()) {
			Fruit fruit = iterator.next();
		}
	}
	
	class DescendingComparator implements Comparator<Fruit> {

		@Override
		public int compare(Fruit o1, Fruit o2) {
			if(o1.price <o2.price) return 1;
			else if(o1.price == o2.price) return 0;
			else return -1;
		}
	}
	
	class Fruit  {
		public String name;
		public int price;
		
		public Fruit(String name, int price) {
			this.name = name;
			this.price = price;
		}
	}
}

LIFO FIFO 클래스

Stack클래스

특징

- 후입선출 구조

- JVM스택 메모리

 

주요메소드

- push() 주어진 객체를 스택에 넣는다.

- peek() 스택의 맨위 객체를 가져온다. 객체를 스택에서 제거하지는 않는다.

- pop() 스택의 맨위 객체를 가져온다. 객체를 스택에서 제거한다.

 

Queue인터페이스

특징

- 선입선출

- 응용 예: 작업큐, 메시지큐, ...

- 구현클래스 : LinkedList

 

주요메소드

- offer() 주어진 객체를 넣는다.

- peek() 객체 하나를 가져온다. 제거x

- poll() 객체 하나를 가져온다. 제거O

 

동기화된 컬렉션

비동기화된 컬렉션을 동기화된 컬렉션을 래핑

List 컬렉션

List<T> list = Collections.synchronizedList(new ArrayList<T>());

Set 컬렉션

Set<E> set = Collections.synchronizedSet(new HashSet<E>());

 

 

남궁성,『Java의 정석』,도우출판