Chapter 16. Collection Framwork

김승현·2021년 10월 2일
0

Collection (컬렉션) 이란?


  • 메모리상에서 자료를 구조적으로 처리하는 방법을 자료구조라고 한다.
  • 컬렉션은 자바에서 제공하는 자료 구조를 담당하는 프레임워크이다.
    ※ 프레임워크(Framework) : 개발을 수월하게 하기 위하여 다양한 기능을 제공하는 도구나 틀 (Collection은 객체)
  • 데이터의 추가, 삭제, 정렬 등의 기능처리가 간단하게 해결되어 개발자가 자료구조적 알고리즘을 별도로 구현할 필요가 없다.
  • 데이터(자료)를 메모리에서 구조적, 효율적으로 처리하기 위한 방법론



배열(Array)의 한계점 과 컬렉션(Collection)의 장점


  • 배열의 한계점

    • 한번 크기를 정하면 크기 변경 불가
    • 배열에 기록된 데이터에 대한 중간 위치에 추가 및 삭제의 어려움
    • 한 타입의 데이터만 저장 가능
  • 컬렉션의 장점

    • 저장하는 크기의 제약 없음
    • 추가, 삭제, 정렬 등의 기능 처리의 간단한 구현 가능
    • 자료구조가 내장되어 알고리즘 구현이 별도로 필요 없음
    • 다양한 타입을 저장 가능(객체 타입 -> 기본 자료형은 Wrapper Class 활용)



컬렉션의 주요 인터페이스


  • 컬렉션은 크게 2개의 인터페이스로 나눌 수 있다.
    • Collection, Map

Collection 계열

  • List 계열(ArrayList, Vector, LinkedList)
    • 순서를 유지하고 순차적으로 데이터를 저장
    • 중복된 데이터 저장 가능
  • Set 계열(HashSet, TreeSet)
    • 순서를 유지하지 않고, 데이터를 저장
    • 중복된 데이터 저장 불가능
  • Queue 계열(PriorityQueue)
    • FIFO 구조(Fisrt in First Out)
    • 들어온 순서대로 데이터를 저장하고 뺄 수 있음\

Map 계열

  • List와 Set을 합친 구조
  • 키와 값 이용하여 데이터를 저장
    ※ 키는 중복 안됨 , 값은 중복 가능
  • HashMap, HashTable, TreeMap, Properties



ArrayList


  • ArrayList는 기존 배열(Array)처럼 순차적으로 데이터를 저장하고 사용할 수 있으나, 길이가 정해져 있지 않음 (계속적인 데이터 추가 가능)

    다양한 메소드를 사용하여 List 기능을 사용 가능

    • add(데이터) : 데이터 추가(정상적으로 추가 될 경우 true, 실패 시 false 리턴)
    • size() : ArrayList의 사이즈 확인
    • get(index) : 특정 index의 데이터를 꺼내옴
    • set(index, 데이터) : 특정 index에 데이터 넣음
    • remove(index) : 특정 index의 데이터 삭제
    • clear(): 전체 데이터 삭제
    • isEmpty(): list안에 데이터가 있는지 여부 체크(있으면 true, 없으면 false 리턴)
    • sort(데이터) : 데이터 정렬(정렬 시에는 Collections Class에서 제공하는 sort 메소드를 사용해야함)



  • Ex)
package com.test.run;

import java.util.ArrayList;

public class TestMain {

	public static void main(String[] args) {

		ArrayList list = new ArrayList();

		// 데이터 저장
		list.add(100);
		System.out.println("데이터 : " + list); // 출력: [100]

		// 저장된 데이터 수 출력
		System.out.println("길이 : " + list.size()); // 출력 : 1
		System.out.println();

		list.add(200);
		System.out.println("데이터 : " + list); // 출력: [100, 200]
		System.out.println("길이 : " + list.size()); // 출력 : 2
		System.out.println();

		list.add(300);
		System.out.println("데이터 : " + list); // 출력: [100, 200, 300]
		System.out.println("길이 : " + list.size()); // 출력 : 3

		// 데이터 지우기(0~)
		list.remove(1);
		System.out.println("데이터 : " + list); // 출력: [100, 300]
		System.out.println("길이 : " + list.size()); // 출력: 2

		// 데이터 꺼내오기
		System.out.println("index 1번째 데이터 출력 : " + list.get(1)); // 출력: 300

		// 데이터 수정
		list.set(1, 999);
		System.out.println("데이터 : " + list); // 출력: [100, 999]

		
		
		// 데이터 존재 여부 확인
		System.out.println("데이터 존재 여부 : " + list.isEmpty()); // 출력 : false

		// 데이터 전체 삭제
		list.clear();

		// 전체 삭제 후 데이터 존재 여부 확인
		System.out.println("데이터 존재 여부 : " + list.isEmpty()); // 출력 : true

		System.out.println("데이터 : " + list); // 출력: []
		System.out.println("길이 : " + list.size()); // 출력: 0
	}
}



Ex) ArrayList의 응용(Member 객체를 만들어서 add와 get 사용)

package com.test.run;

import java.util.ArrayList;

class Member{
	private String name;
	private int age;
	private String addr;

	public Member() {
	}

	public Member(String name, int age, String addr) {
		this.name = name;
		this.age = age;
		this.addr = addr;
	}

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

	public String getAddr() {
		return addr;
	}

	public void setAddr(String addr) {
		this.addr = addr;
	}

	@Override
	public String toString() {
		return name + "/" + age + "/" + addr;
	}

}

public class TestMain {

	public static void main(String[] args) {
		
		//방법 1
		ArrayList list1 = new ArrayList();	// 들어오는 데이터 Object 객체 타입으로 저장
		
		list1.add(new Member("홍길동", 20, "경기도 부천"));
		list1.add(new Member("김말똥", 30, "경기도 안양"));
		list1.add(new Member("고길똥", 40, "부산시 서면"));
		
		//list1.get(0).getName();	// 데이터가 Object 타입으로 저장 되있기 때문에 자식 Class인 Member Class의 메소드에 접근할 수 없다.
		
		((Member)list1.get(0)).getName();	// 다운 캐스팅을 통하여 호출하여야 한다.

		
		// 방법 2
		ArrayList<Member> list2 = new ArrayList<Member>();	// 들어오는 데이터 Member 객체 타입으로 저장

		list2.add(new Member("홍길동", 20, "경기도 부천"));
		list2.add(new Member("김말똥", 30, "경기도 안양"));
		list2.add(new Member("고길똥", 40, "부산시 서면"));
		
		list2.get(0).getName();	// Memeber Class의 getName 메소드 호출

		// 이름, 나이, 주소 개별 출력	
		for (Member m : list2) {
			System.out.println("이름 : " + m.getName());
			System.out.println("나이 : " + m.getAge());
			System.out.println("주소 : " + m.getAddr());
			System.out.println();
		}

	}
}
  • 방법1: ArrayList 객체 생성 시Object 객체로 데이터 저장이 되기 때문에 Member Class에 접근하려면 다운캐스팅을 해야 한다.
  • 방법 2: ArrayList 객체 생성 시 제네릭을 이용하여 Member 객체로 데이터 저장을 설정하여 Member Class 내부 정보에 접근하기 용이하다.



  • Ex) 정수 정렬하기(sort)
package com.test.run;

import java.util.ArrayList;
import java.util.Collections;

public class TestMain {

	public static void main(String[] args) {
		
		ArrayList<Integer> list = new ArrayList<Integer>();
		
		list.add(10);
		list.add(5);
		list.add(87);
		list.add(8);
		list.add(2);
		list.add(11);
		
		System.out.println(list);	// 출력값: [10, 5, 87, 8, 2, 11]

		//오름차순 정렬
		Collections.sort(list);
		System.out.println(list);	// 출력값: [2, 5, 8, 10, 11, 87]
		
		//내림차순 정렬
		Collections.sort(list,Collections.reverseOrder());
		System.out.println(list);	// 출력값: [87, 11, 10, 8, 5, 2]

	}
}
  • list에 저장된 데이터를 정렬할때에는 sort 를 사용하여 손쉽게 정렬할 수 있다.
  • 단, 들어있는 데이터가 정수일 때 만 가능하다.
  • 그렇다면 객체를 정렬하고 싶다면?(ex. Member 객체)
  • Member 객체를 가지고 정렬할 수 있도록 기준을 정해 주어야 한다.
    - 기준을 정해주는 방법은 Member Class에 Comparable Interface를 implements를하고 compartTo()메소드를 오버라이딩(재정의)해야한다.



  • Ex) 객체 정렬하기 (sort)
package com.test.run;

import java.util.ArrayList;
import java.util.Collections;

class Member implements Comparable { // 객체 정렬을 위한 compareTo() 사용하기 위해 Comparable 인터페이스 implements 하기
	
	private String name;
	private int age;
	private String addr;

	public Member() {
	}

	public Member(String name, int age, String addr) {
		this.name = name;
		this.age = age;
		this.addr = addr;
	}

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

	public String getAddr() {
		return addr;
	}

	public void setAddr(String addr) {
		this.addr = addr;
	}

	@Override
	public String toString() {
		return name + "/" + age + "/" + addr;
	}

	@Override
	public int compareTo(Object o) {

		return this.name.charAt(0) - ((Member) o).getName().charAt(0);	// 이름을 기준으로 내림차순
		//return ((Member) o).getName().charAt(0)-this.name.charAt(0);	// 이름을 기준으로 오름차순
		
	}
}

public class TestMain {

	public static void main(String[] args) {

		ArrayList<Member> list = new ArrayList<Member>();

		list.add(new Member("홍길동", 20, "경기도 부천"));
		list.add(new Member("고길똥", 40, "부산시 서면"));
		list.add(new Member("김말똥", 30, "경기도 안양"));
		


		System.out.println(list);	// [홍길동/20/경기도 부천, 고길똥/40/부산시 서면, 김말똥/30/경기도 안양]
		// 정렬
		Collections.sort(list);
		System.out.println(list);	// [고길똥/40/부산시 서면, 김말똥/30/경기도 안양, 홍길동/20/경기도 부천]

	}
}



HashSet


  • Set의 인터페이스중 가장 대표적인 컬렉션
  • 저장 순서가 유지되지 않고, 중복 데이터(객체)를 저장할 수 없는 자료 구조
    • 중복된 데이터 추가시 false값 리턴, 중복 데이터가 아니라면 데이터 저장하고 true 리턴
    • null 값도 중복 허용하지 않음
  • 순서대로 저장하는 것이 아니기 때문에 List처럼 index로 접근 불가
  • 반복문을 이용해서 데이터 저장시 원하는 개수의 데이터가 안 담길 수 있다.
  • 대표 메소드
  • add(데이터) : 데이터 추가(삽입시 true, 실패시 false 리턴)
    • clear() : 모든 데이터 삭제
    • isEmpty() : 데이터 존재 여부 확인(없으면 true, 있으면 false 리턴)
    • size() : 현재 저장된 데이터 개수 리턴



  • Ex)
package com.test.run;

import java.util.HashSet;

public class TestMain {

	public static void main(String[] args) {

		HashSet set = new HashSet();
		
		// 데이터 추가
		System.out.println(set.add(100));	// 출력: true
		System.out.println(set);			// 출력: [100]
		System.out.println(set.add(200));	// 출력: true
		System.out.println(set);			// 출력: [100, 200]
		System.out.println(set.add(300));	// 출력: true
		System.out.println(set);			// 출력: [100, 200, 300]
		System.out.println(set.add(400));	// 출력: true
		
		// 중복값 추가
		System.out.println(set.add(400));	//출력: false
		
		// 데이터 출력(데이터 입력 순서 유지 되어 저장하지 않는다)
		System.out.println(set);	// 출력: [400, 100, 200, 300] 
		
		// 현재 저장된 데이터 개수 출력
		System.out.println(set.size());		// 출력 : 4
		
		// 데이터 존재 여부 확인
		System.out.println(set.isEmpty());	// 출력 : false (데이터 있음)
		
		// 데이터 전체 삭제
		set.clear();
		
		// 데이터 전체 삭제 후 데이터 존재 여부 확인
		System.out.println(set.isEmpty());	// 출력 : true (데이터 없음)
	}
} 
  • HashSet의 데이터 추출
  • HashSet안에 있는 데이터를 사용하기 위해서는 별도의 iterator 라는 메소드를 통해서 데이터를 추출하여 사용 한다.
  • iterator: Set 안에 있는 데이터를 Token 형태로 꺼낼 수 있도록 하는 구조(원본에 영향 없다)
    • hasNext() : Iterator가 가지고 있는 메소드로써 다음 Token이 있는지 확인(있으면 true, 없으면 false 리턴)
    • next() : Iterator가 가지고 있는 메소드로써 다음 Token을 추출하다.
  • ArrayList를 활용하여서도 데이터 추출할 수 있다.
    • 데이터 정렬하여 추출 가능하다



  • Ex) 데이터 추출 : iterator() 메소드 사용
package com.test.run;

import java.util.HashSet;
import java.util.Iterator;

public class TestMain {

	public static void main(String[] args) {

		HashSet set = new HashSet();

		System.out.println(set.add(100));
		System.out.println(set.add(200));
		System.out.println(set.add(600));
		System.out.println(set.add(800));
		System.out.println(set);	// 출력: [800, 100, 200, 600]

		// set에 저장된 데이터를 꺼내려면 iterator화 시켜야 한다.-> 토근 형태로 추출
		Iterator data = set.iterator();

		// 저장된 데이터 있는지 확인-> 데이터가 없다면 반복분 종료
		while (data.hasNext()) {
			// 데이터 1개씩 출력
			System.out.println(data.next());	// 출력 총 4번-> 800. 100, 200, 600 하나씩 출력
		}
	}
}



  • Ex) 데이터 추출 : ArrayList 사용
package com.test.run;

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;

public class TestMain {

	public static void main(String[] args) {

		HashSet set = new HashSet();

		set.add(100);
		set.add(200);
		set.add(600);
		set.add(800);
		System.out.println("set 데이터 : " + set); // 출력 : set 데이터 : [800, 100, 200, 600]

		// set 데이터 list 데이터로 변환
		ArrayList list = new ArrayList(set);

		// 데이터 오름차순 정렬
		Collections.sort(list);

		// 총 데이터 출력
		System.out.println("list 데이터 : " + list); // 출력 : list 데이터 : [100, 200, 600, 800]

		// 저장되 데이터의 수 만큼 반복하여 인텍스에 저장된 데이터 출력
		for (int i = 0; i < list.size(); i++) {
			System.out.println(list.get(i));	// 출력: 100
							//	200
							//	600
							//	800
		}
	}
}
  • ArrayList와 HashSet을 조합하면 좋은 점
    • 중복된 데이터는 저장하지 않는다.
    • 손쉽게 데이터를 꺼내 쓸 수 있다.
    • 정렬이 가능하다.



HashMap


  • Map의 대표적인 컬렉션
  • 키(Key)와 값(Value)으로 구성 되어있다. (Key, Value 모두 객체 타입)
  • Key: 중복 저장 불가 / Value: 중복 저장 가능
  • Key가 중복되는 경우: 기존에 있는 키에 해당하는 Value를 덮어 쓴다.
  • 데이터 저장: 비순차적
  • HashMap 주요 메소드
    • put(key, value) : 데이터 삽입
    • get(key) : key값에 해당하는 Value 값 추출
    • remove(key) : key값으로 데이터 찾아 key, value 삭제
    • containsKey(key) : key값의 존재 여부 확인 (있으면 true, 없으면 false)
    • keySet() : key값들만 따로 추출하여 set형태로 저장



  • Ex)
package com.test.run;

import java.util.HashMap;

public class TestMain {

	public static void main(String[] args) {

		HashMap map = new HashMap();

		// 데이터 저장
		map.put(1, "홍길동");
		map.put(2, "이미숙");
		map.put(3, "김숙자");

		// 전체 데이터 출력
		System.out.println(map); // 출력 : {1=홍길동, 2=이미숙, 3=김숙자}

		// 중복 데이터 삽입
		map.put(3, "김말똥");
		System.out.println(map); // 출력 : {1=홍길동, 2=이미숙, 3=김말똥}

		// key값에 해당하는 value 데이터 추출
		System.out.println(map.get(1)); // 출력 : 홍길동

		// key값에 해당하는 데이터 삭제
		map.remove(1);
		System.out.println(map); // 출력 : {2=이미숙, 3=김말똥}

		// 중복 key값 확인(있으면 true, 없으면 false)
		System.out.println(map.containsKey(2)); // 출력 : true
		System.out.println(map.containsKey(5)); // 출력 : false

	}
}



  • Ex) keySet 메소드 활용
package com.test.run;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Set;

class Member {
	private String name;
	private String addr;
	private int age;

	public Member() {
	}

	public Member(String name, int age, String addr) {
		this.name = name;
		this.addr = addr;
		this.age = age;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public String getAddr() {
		return addr;
	}

	public void setAddr(String addr) {
		this.addr = addr;
	}

	public int getAge() {
		return age;
	}

	public void setAge(int age) {
		this.age = age;
	}

	@Override
	public String toString() {
		return name + "/" + age + "/" + addr;
	}
}

public class TestMain {

	public static void main(String[] args) {
		HashMap map = new HashMap();

		map.put(100, new Member("홍길동", 20, "경기도 안양시"));
		map.put(200, new Member("김말숙", 30, "부산시 서면"));
		map.put(300, new Member("이요동", 40, "강원도 강릉시"));

		// key 값만 추출하여 set으로 대입
		Set set = map.keySet();

		// ArrayList
		ArrayList list = new ArrayList(set);

		for (int i = 0; i < list.size(); i++) {
			System.out.println("key : " + list.get(i) + " / value : " + map.get(list.get(i)));

			// 출력: key : 100 / value : 홍길동/20/경기도 안양시
			// 출력: key : 200 / value : 김말숙/30/부산시 서면
			// 출력: key : 300 / value : 이요동/40/강원도 강릉시
		}
	}
}



  • Ex) 제네릭 활용
package com.test.run;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Set;

class Member {
	private String name;
	private String addr;
	private int age;

	public Member() {
	}

	public Member(String name, int age, String addr) {
		this.name = name;
		this.addr = addr;
		this.age = age;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public String getAddr() {
		return addr;
	}

	public void setAddr(String addr) {
		this.addr = addr;
	}

	public int getAge() {
		return age;
	}

	public void setAge(int age) {
		this.age = age;
	}

	@Override
	public String toString() {
		return name + "/" + age + "/" + addr;
	}
}

public class TestMain {

	public static void main(String[] args) {

		// key값, value값 모두 Object 타입으로 객체 저장
		HashMap map1 = new HashMap();
		map1.put(100, new Member("홍길동", 20, "경기도 안양시"));
		map1.put(200, new Member("김말숙", 30, "부산시 서면"));
		map1.put(300, new Member("이요동", 40, "강원도 강릉시"));

		// Member 객체의 데이터에 접근하려면 다운 캐스팅을 해야한다.
		((Member) map1.get(100)).getName();

		// 제네릭 활용(key값 Integer 타입, value값 Member 타입으로 데이터 저장
		HashMap<Integer, Member> map2 = new HashMap<Integer, Member>();

		map2.put(100, new Member("홍길동", 20, "경기도 안양시"));
		map2.put(200, new Member("김말숙", 30, "부산시 서면"));
		map2.put(300, new Member("이요동", 40, "강원도 강릉시"));

		// Member 객체의 데이터에 바로 접근 가능하다.
		map2.get(100).getName();

	}
}



  • Ex) keySet 메소드, 제네릭 활용
package com.test.run;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Set;

class Member {
	private String name;
	private int age;
	private String addr;

	public Member() {
	}

	public Member(String name, int age, String addr) {
		this.name = name;
		this.age = age;
		this.addr = addr;
	}

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

	public String getAddr() {
		return addr;
	}

	public void setAddr(String addr) {
		this.addr = addr;
	}

	@Override
	public String toString() {
		return name + "/" + age + "/" + addr;
	}

}

public class TestMain {

	public static void main(String[] args) {

		HashMap<Integer, Member> map = new HashMap<Integer, Member>();

		map.put(100, new Member("홍길동", 20, "경기도 부천"));
		map.put(110, new Member("김말똥", 30, "서울시 양천"));
		map.put(150, new Member("고길똥", 40, "부산시 서면"));

		Set set = map.keySet();

		ArrayList keyList = new ArrayList(set);

		ArrayList<Member> list = new ArrayList<Member>();

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

			list.add(map.get(keyList.get(i)));
		}

		for (Member m : list) {
			System.out.println(m);
		}
	}
}



Properties


  • 키(key)와 값(value)를 String 타입으로 제한한 Map 형태의 컬렉션

  • 별도의 프로퍼티(Properties)파일을 읽어 들여서 데이터를 처리함

  • Properties 파일은 key=value의 값의 쌍들로 이루어지며, 별도의 파일로 데이터를 저장하고, 파일의 확장자는 .properties를 사용한다.

  • Properties 파일 만들기

    • Source Folder 생성 -> File 생성(확장자: .properties) -> key=value의 형태로 작성
  • 객체생성 및 메소드

    • 객체 생성
      • ex) new Properties 변수명 = new Properties();
    • Properties 불러오기
      • 변수명.load(new FileReader(“properties 파일 위치”)); : 예외처리 필수
    • value 값 불러오기
      • 변수명.getProperties(“key”);



  • ex)

    • MemberController Class

package com.test.run;

import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Properties;

class MemberController {
	
	
	private ArrayList<String> list = new ArrayList<String>();
	String dbId = "user11"; // DB의 ID
	String dbPw = "159159"; // DB의 PW

	
	
	public MemberController() {
		list.add("홍길동");
		list.add("김말똥");
		list.add("고길동");
		list.add("유비");
		list.add("장비");
		list.add("관우");
	}

	public void start() {

		//properties 파일에 있는 내용을 읽어서 가져오도록 하겠습니다.
		Properties prop = new Properties();
		
		try {
			prop.load(new FileReader("resources/Login.Properties"));
		} catch (IOException e) {
			e.printStackTrace();
		}
		
		String id=prop.getProperty("id");
		String pw=prop.getProperty("pw");
		
		// DB에 정상 연결 하였는지!
		boolean result = getDbCopnnection(id, pw);

		if (result == true) {
			System.out.println("----- 고객 정보 출력 -----");
			for (String name : list) {
				System.out.println(name);
			}
		} else {
			System.out.println("DB 연결 실패!(ID/PW 확인 요망)");
		}
	}

	public boolean getDbCopnnection(String id, String pw) {
		// 해당 메소드는 id와 pw를 보내서 DB와 일치한다면
		// true 리턴, 일치하지 않다면 false 리턴

		if (id.equals(dbId) == true == pw.equals(dbPw)) {
			return true;
		} else {
			return false;
		}
	}
}

public class TestMain {

	public static void main(String[] args) {
		new MemberController().start();

	}
}
  • LoginProperties
id=goCom
pw=1q2w3e
profile
개발자로 매일 한 걸음

0개의 댓글