본문 바로가기

Java/기본 개념

컬렉션(Collection)

▶ 컬렉션 (Collection)

  • 컬렉션(Collection)은 자바에서 제공하는 자료구조를 담당하는 프레임워크
    ※ 자료구조: 메모리에서 자료를 구조적으로 처리하는 방법
  • 추가, 삭제, 정렬 등의 기능처리가 간단하게 해결되어 자료구조적 알고리즘을 구현할 필요 없음
  • java.util 패키지에 포함되며, 인터페이스를 통해 정형화된 방법으로 다양한 컬렉션 클래스 이용 가능

▶ 배열의 문제점 & 컬렉션의 장점

1) 배열의 문제점

  • 한번 크기를 지정하면 변경할 수 없음
    - 필요에 따라 공간을 늘리거나 줄일 수 없음
  • 배열에 기록된 데이터에 대한 중간 위치의 추가, 삭제가 불편함
    - 추가, 삭제할 데이터부터 마지막에 기록된 데이터까지 하나씩 뒤로 밀어내고 추가(복잡한 알고리즘)
  • 한 타입의 데이터만 저장 가능함

2) 컬렉션의 장점

  • 저장하는 크기의 제약 없음
  • 추가, 삭제, 정렬 등 기능 처리가 간단하게 해결
    - 자료를 구조적으로 처리하는 자료구조가 내장되어 있어 알고리즘 구현 필요 없음
  • 여러 타입의 데이터 저장 가능
    - 객체만 저장할 수 있기 때문에 필요에 따라 기본 자료형을 저장해야 하는 경우, Wrapper 클래스 사용

▶ List

  • 여러 자료를 순차적으로 나열한 자료구조 (배열과 비슷)
  • 인덱스로 관리(순서 구분)되며, 중복해서 객체 저장 가능
  • 구현 클래스 : ArrayList, Vector, LinkedList

1) List 계열 주요 메소드

public void ex1() {
   // 다형성 적용
		
   List list = new ArrayList(3); // 3칸 짜리 생성
   // List list = new ArrayList(); // 기본형 : 10칸짜리 생성
		
   // 1. boolean add(E e) : 마지막 요소로 추가
   // E(Element) : 요소를 뜻하는 상징적인 글자 (자료형 X)
		
   list.add("아무거나"); // String은 객체
		
   // Auto Boxing (자동 포장)
   list.add(123); // int -> Integer
   list.add(3.14); // double -> Double
   // ★ 컬렉션에 저장되는 객체의 타입 제한 X
   // 왜 기본 자료형이 저장될까?
   // -> Wrapper Class : 기본 자료형 -> 객체로 포장하는 클래스
		
   System.out.println(list); // 참조변수 print구문으로 출력 시 toString() 결과값 출력
   // list의 크기 3 초과해서 추가해도
   // 자동으로 크기가 늘어나기 때문에 에러 발생 X
		
   // 2. E get(int index) : 지정한 index 요소 얻어오기
   System.out.println(list.get(1));
   System.out.println(list.get(0));
   System.out.println(list.get(2));
		
   System.out.println("------------------------------");
   		
   // 예제 - 진짜 자동 포장(Auto Boxing) 되었는가 확인
		
   System.out.println(list.get(1) instanceof Integer); // true
   System.out.println(list.get(2) instanceof Double); // true
}
public void ex2() {
   // 컬렉션의 장점 중 "여러 타입 저장 가능" 때문에 
   // instanceof로 타입 검사를 해야하는 코드가 추가되어
   // 코드의 길이가 늘어나는 문제점이 발생
   // -> 타입을 하나로 제한하자!
   // --> Generics(제네릭)을 이용
		
   // String으로 저장되는 타입이 제한된 List
		
   List<String> list = new ArrayList<String>();
		
   list.add("파닭");
   list.add("마파두부");
   list.add("불고기");
   list.add("라멘");
   list.add("서브웨이");
		
// 3. list.add(int index, E e) : 중간에 추가(삽입)
   list.add(0,"짜장면");
   list.add(3,"탕수육");
   
   System.out.println(list); 
   // 결과값 : [짜장면, 파닭, 마파두부, 탕수육, 불고기, 라멘, 서브웨이]
		
// 4. E list.set(int index, E e) : 
   // 지정된 index의 요소를 바꿈(수정)
   // 반환되는 값은 바뀌기 이전 요소
		
   String before = list.set(1, "닭갈비");
   
   System.out.println("before : " + before);
   // 결과값 : before : 파닭
   System.out.println(list);
   // 결과값 : [짜장면, 닭갈비, 마파두부, 탕수육, 불고기, 라멘, 서브웨이]
		
// 5. E list.remove(int index) :
   // index번째 요소를 List에서 제거
   // 반환되는 값은 제거된 요소
		
   String target = list.remove(6);
		
   System.out.println(target + " 제거");
   // 결과값 : 서브웨이 제거
		
// 6. boolean list.contains(E e) : 
   // list에 요소가 포함되어 있는지 확인
		
   System.out.println(list.contains("닭갈비"));
   // 결과값 : true
   System.out.println(list.contains("파닭"));
   // 결과값 : false
		
// 7. int list.indexOf(E e) :
   // list에 요소가 존재하면 해당 index 반환
   // 없으면 -1 반환
		
   System.out.println(list.indexOf("닭갈비"));
   // 결과값 : 1
   System.out.println(list.indexOf("파닭"));
   // 결과값 : -1
  
  System.out.println(list);
   // 결과값 : [짜장면, 닭갈비, 마파두부, 탕수육, 불고기, 라멘]
   for(int i=0; i<list.size(); i++) {
   // list.get(i)
   // -> String으로 제한된 리스트에서 요소를 꺼내오기 때문에
   //    꺼낸 요소의 자료형은 무조건 String
   System.out.printf("[%d] : %s \n", i, list.get(i));
   }
   // 결과값 : [0] : 짜장면 
              [1] : 닭갈비 
              [2] : 마파두부 
              [3] : 탕수육 
              [4] : 불고기 
              [5] : 라멘

// 8. void list.clear() : 요소 모두 삭제
   list.clear();
   System.out.println(list);
   // 결과값 : []
		
// 9. boolean list.isEmpty() :
   // 비어있으면 true, 아니면 false
   System.out.print("list는 비어 있는가? " + list.isEmpty());
   // 결과값 : list는 비어 있는가? true
}

2) ArrayList

  • List의 자손 클래스로 초기 저장 용량은 10으로 자동 설정되며 따로 지정도 가능
  • 저장 용량을 초과한 객체가 들어오면 자동으로 늘어나며 고정도 가능
  • 동기화(Synchronized)를 제공하지 않음

3) LinkedList

  • List의 자손 클래스로 인접 참조를 링크해 체인처럼 관리함
  • 특정 인덱스에서 객체를 제거하거나 추가하게 되면, 바로 앞/뒤 링크만 변경하면 되기 때문에
    객체 삭제와 삽입이 빈번하게 일어나는 곳에서 ArrayList보다 성능이 좋음

4) Comparable / Comparator

  Comparable Comparator
패키지 java.lang java.util
사용 메소드 compareTo( ) compare( )
정렬 기본 정렬기준을 구현하는데 사용 그 외 다른 여러 기준으로 정렬하고자 할 때 사용
사용법 정렬하고자 하는 객체에 Comparable를 상속받아
compareTo( ) 메소드를 오버라이딩해서 기본 정렬 기준 재정의
→ 한 개의 정렬만 가능함
Model.sort 패키지 안에 필요한 정렬 기준에 맞춘
여러 클래스를 생성하고 Comparator를 상속받아
Compare( ) 메소드를 오버라이딩해서 정렬 기준 재정의
→ 여러 개 정렬 가능

5) Collections.sort( )

  • Collections.sort( List<T> list ) : T 객체에 Comparable을 상속받아
    compareTo 메소드 재정의를 통해 정렬 구현(단 한 개의 정렬)
  • Collections( List<T> list, Comparator<T> c ) : 지정한 Comparator 클래스에 의한 정렬(여러 개의 정렬)

▶ Set

  • 저장 순서가 유지되지 않고(인덱스 없음), 중복 객체도 저장하지 못하게(같은 객체를 덮어씌움) 하는 자료구조
  • get( ) 메소드 없음
  • null도 중복을 허용하지 않기 때문에 1개의 null만 저장
  • 구현 클래스 : HashSet, LinkedHashSet, TreeSet

1) Set 계열 주요 메소드

2) HashSet

  • Set에 객체를 저장할 때, Hash 함수를 사용하여 처리속도가 빠름
  • 동일 객체뿐만 아니라, 동등 객체도 중복해서 저장 X
  • hashCode( )를 이용해서 중복 비교 → hashCode( ) 오버라이딩 필수 → 빠른 검색 지원

3) LinkedHashSet

  • 순서가 유지되는 Set
  • hashCode( ) 오버라이딩 필수

4) TreeSet

  • 저장되는 값을 자동으로 정렬
  • Comparable 상속 필수
public void ex1() {
// 기본적인 Set 사용법
		
// String, Integer 등 Java 제공 객체는
// 기본적으로 hashCode(), equals(), campareTo() 등이
// 오버라이딩 되어 있음
		
   Set<String> set = new HashSet<>();
   // Cannot instantiate the type Set (인터페이스 = 미완성 설계도 -> 객체 생성 X)
		
// 1. boolean set.add(E e) : 추가
   set.add("네이버");
   set.add("카카오");
   set.add("라인");
   set.add("쿠팡");
   set.add("배달의 민족");
   set.add("당근마켓");
   set.add("토스");
   System.out.println(set);
   // 결과값 : [배달의 민족, 당근마켓, 카카오, 네이버, 쿠팡, 라인, 토스]
   // HashSet 순서 유지 X
		
   // 중복 저장 확인 -> 중복 저장 X
   set.add("토스");
   set.add("토스");
   set.add("토스");
   set.add("토스");
   set.add("토스");
   set.add("토스");
   System.out.println(set);
   // 결과값 : [배달의 민족, 당근마켓, 카카오, 네이버, 쿠팡, 라인, 토스]
		
   // set에 null도 저장이 되는지 확인 -> 저장 O (단, 중복 저장은 X)
   set.add(null);
   System.out.println(set);
   // 결과값 : [null, 배달의 민족, 당근마켓, 카카오, 네이버, 쿠팡, 라인, 토스]
		
// 2. int set.size() : 저장된 객체의 수 반환
   System.out.println(set.size() + "개");
   // 결과값 : 8개	
		
// 3. boolean remove(E e) : 
   // e와 똑같은 요소가 set에 있으면 지우고 true 반환
   // 없으면 false 반환
   if(set.remove(null)) {
       System.out.println("null이 제거되었습니다.");
   } else {
       System.out.println("null이 없습니다.");
   }
   System.out.println(set);
   // 결과값 : [배달의 민족, 당근마켓, 카카오, 네이버, 쿠팡, 라인, 토스]
		
// 4. boolean set.contains(E e) :
   // set에 저장된 객체 중에서 e와 똑같은 객체가 있으면 true, 아니면 false 반환
   System.out.println("네이버 "+(set.contains("네이버")? "있음" : "없음"));
   // 결과값 : 네이버 있음
   System.out.println("직방 "+(set.contains("직방")? "있음" : "없음"));
   // 결과값 : 직방 없음
		
// 5. void set.clear() : set에 저장된 객체를 모두 지움
   set.clear();
   System.out.println("clear 후 size : " + set.size());
   // 결과값 : clear 후 size : 0
		
// 6. boolean set.isEmpty() :
   // set에 저장된 객체가 없다면(비어있다면) true, 아니면 false 반환
   // "set.size() == 0" 과 같은 의미
		
   System.out.println("set이 "+(set.isEmpty()? "비어있음" : "비어있지 않음"));
   // 결과값 : set이 비어있음
}
public void ex2() {
// Set에 저장된 값을 꺼내쓰는 방법
		
// 1. Iterator (반복자)
   // - 컬렉션 객체의 요소를 하나씩 꺼내서 반복 접근할 수 있는 객체
   // 	 (순서대로 요소 하나씩 꺼내는 객체)
		
   Set<String> set = new HashSet<>();
   set.add("쌀과자");
   set.add("오예스");
   set.add("초코파이");
   set.add("몽쉘");
   set.add("빅파이");
		
   // Iterator set.iterator(); :
   // set의 내용을 순차(반복) 접근할 수 있는 형태로 변경해서 반환
   Iterator<String> it = set.iterator();
		
   // boolean it.hasNext() : 
   // 다음 꺼낼 요소가 있으면 true, 없으면 false 반환
		
   while(it.hasNext()) { // 하나씩 꺼냈을 때 다음 값이 없는 경우 == 끝
						 // -> 다음 값이 있으면 반복!
   String temp = it.next(); // E it.next() : 다음 요소 꺼내서 반환
   System.out.println(temp);
   // 결과값 : 오예스
              쌀과자
              빅파이
              초코파이
              몽쉘
   }
   
System.out.println("------------------------------------------");
		
// 2. 향상된 for문
   for(String s : set) {
   System.out.println(s);
   // 결과값 : 오예스
              쌀과자
              빅파이
              초코파이
              몽쉘
   }
}
public class Student {
   // A.equals(B)
   // A 객체와 B 객체가 가지고 있는 필드의 값이 모두 같으면 true, 아니면 false
   @Override // Object.equals() 오버라이딩
   public boolean equals(Object obj) {
      if(this == obj) {
         return true;
      } 
      if(obj==null) { 
         return false;
      }
      if(!(obj instanceof Student)) { // 비교 대상이 Student가 아니라면
         return false;
      }
      // obj 참조변수를 Student로 다운 캐스팅
      Student other = (Student)obj;
      // 현재 객체(this)와 다른 객체(other)의 필드를 비교
      return this.grade == other.grade
           && this.ban == other.ban
           && this.number == other.number
           && this.name.equals(other.name)
           && this.gender == other.gender
           && this.score == other.score;
   }
   // (중요!!) equals() 오버라이딩 했으면
   // hashCode()도 오버라이딩을 해야 한다!!
	
   // hashCode() : 해시 테이블(객체 주소록)에서 
   // 			    객체를 빨리 찾아가게 하기 위한 번호
   
   //****************************************
   // * A.equals(B)의 결과가 true 라면
   // * A.hashCode() == B.hashCode() 의 결과도 treu여야 한다.
   //****************************************
	
   @Override // Object의 hashCode() 오버라이딩
   public int hashCode() {
   // 필드 값이 같은 객체는 같은 정수를 반환해야 한다.
   // == 필드 값을 이용해서 정수를 만들면 된다.
   int result = 1; // 결과 저장 변수
   final int PRIME = 31; // 31이 연산속도가 빠른 소수 중 하나
   result = result * PRIME * ban;
   result = result * PRIME * (name == null ? 0 : name.hashCode());
   return result;
   }
}

public void ex3() {
// Set이 중복을 확인하는 방법
   // -> 새로 추가하려는 객체와 Set에 있는 객체가
   //    equals() 수행 시 true
   //    hashCode() 비교 시 true 이면 중복으로 판단
		
   // ★ Set을 이용하려면 equals()와 hashCode() 필수로 오버라이딩
   // A.equals(B) : A와 B가 가지고 있는 필드 값이 모두 같으면 true, 아니면 false
   // hashCode() : 필드 값이 다르면 중복되지 않는 숫자를 만드는 메소드
   // -> 왜 만들까? 빠른 데이터 검색을 위해서(객체가 어디에 있는지 빨리 찾기 위해서)
		
   // Hash 함수 : 입력된 단어를 지정된 길이의 문자열로 변환하는 함수 (중복 X)
   // ex) 입력 : 123     -> "asdfg" (5글자) 
   // ex) 입력 : 1234567 -> "qwert" (5글자)
		
   // HashSet() : 중복 없이 데이터를 저장(Set)하고 데이터 검색이 빠름(Hash)
		
   Set<Student> set = new HashSet<>();
		
   Student std1= new Student(3,4,5,"홍길동",'M',100);
   Student std2= new Student(3,4,5,"홍길동",'M',100);
   Student std3= new Student(3,4,6,"고길동",'M',100);
		
   set.add(std1);
   set.add(std2);
   set.add(std3);
		
   System.out.println("size : " + set.size());
   // 결과값 : size : 2
		
   for(Student std : set) {
      System.out.println(std);
      System.out.println(std.hashCode());
   }
   System.out.println();
    // 결과값 : [학생정보] 학년: 3, 반: 4, 번호: 5, 이름: 홍길동, 성별: M, 점수: 100
                1571823060
               [학생정보] 학년: 3, 반: 4, 번호: 6, 이름: 고길동, 성별: M, 점수: 100
                367817478
}

▶ Map

  • 특정 키워드(Key)를 입력하면, 해당되는 상세한 값(Value)을 얻을 수 있는 컬렉션 객체
  • K : V 한 쌍으로 데이터를 저장 ( K : V 한 쌍을 묶어서 Entry라고 부름)
  • 키(Key)와 값(Value)으로 구성되어 있으며, 키와 값은 모두 객체
  • 키(Key)는 중복 저장을 허용하지 않고(Set 방식), 값(Value) 는 중복 저장 가능(List 방식)
  • 키(Key) 가 중복되는 경우, 기존에 있는 키(Key) 에 해당하는 값(Value) 를 덮어씌움
  • 구현 클래스 : HashMap, LinkedHashMap, TreeMap

1) Map 계열 주요 메소드

▶ HashMap

  • 키(Key) 객체는 hashCode( )와 equals( )를 오버라이딩해서 동등 객체가 될 조건을 정해야 함
    → 키(Key) 타입은 hashCode( )와 equals( ) 메소드가 재정의되어 있는 String 타입을 주로 사용

  TreeSet과TreeMap

  • 검색 기능을 강화한 컬렉션으로, 계층 구조를 활용해 이진 트리 자료구조를 구현해 제공

public void ex1() {
   // Key 제한, Value 제한
   Map<Integer, String> map = new HashMap<>();		
                                  // Map의 자식 클래스 중 가장 대표되는 Map
		
// 1. V map.put(K k, V v) : Map에 추가
   // Map에 추가 시 Key가 중복되면 새로운 Value로 덮어 씌우고
   // 이전 Value가 반환
   // 중복이 아니면 null 반환
		
   System.out.println(map.put(1, "아이스 바닐라 라떼")); // 결과값 : null
   System.out.println(map.put(2, "아이스 녹차 라떼"));   // 결과값 : null
   System.out.println(map.put(3, "아이스 흑임자 라떼")); // 결과값 : null
   System.out.println(map.put(3, "아이스 흑당 밀크티")); // 결과값 : 아이스 흑임자 라떼
		
   System.out.println(map);
   // 결과값 : {1=아이스 바닐라 라떼, 2=아이스 녹차 라떼, 3=아이스 흑당 밀크티}
		
// 2. V map.get(K k) :
   // map에서 Key에 해당하는 Value를 반환
   // 일치하는 Key가 없으면 null 반환
   System.out.println(map.get(1)); // 결과값 : 아이스 바닐라 라떼
   System.out.println(map.get(2)); // 결과값 : 아이스 녹차 라떼
   System.out.println(map.get(3)); // 결과값 : 아이스 흑임자 라떼
   System.out.println(map.get(4)); // 결과값 : null
		
   // Value가 String이기 때문에 String 변수에 저장 가능
   String s = map.get(1);
		
// 3. int map.size() : 저장된 K:V쌍의 수를 반환
   System.out.println("K:V 몇 쌍? : "+map.size()+"쌍");
   // 결과값 : K:V 몇 쌍? : 3쌍
		
// 4. V map.remove(K k) :
   // map에서 Key가 일치하는 요소(K:V)를 제거
   // 제거되는 Value를 반환, 없으면 null 반환
   System.out.println(map.remove(1)+" 제거");  // 결과값 : 아이스 바닐라 라떼 제거
   System.out.println(map.remove(10)+" 제거"); // 결과값 : null 제거
		
// 5. void map.clear() : map 다 지움
   map.clear();
		
// 6. boolean map.isEmpty() : 비었으면 true, 아니면 false
   System.out.println("map은 비었는가? : "+map.isEmpty());
   // 결과값 : map은 비었는가? : true
}
public void ex2() {
// Map에 저장된 값 순차 접근(반복해서 순서대로 하나씩 꺼내기)
		
// 1. Set map.keySet() : 
   // key만을 모아놓은 집합(Set)을 반환
  
   Map<String, String> map = new HashMap<>();
		
   map.put("학원", "서울시 강남구");
   map.put("롯데월드", "서울시 송파구");
   map.put("스타필드 하남", "경기도 하남시");
		
   Set<String> set = map.keySet();
   System.out.println(set);
   // 결과값 :  // 결과값 : [롯데월드, 스타필드 하남, 학원]
		
   System.out.println("------------------------------");
		
// 2. keySet을 이용해서 Map에 있는 모든 요소 순차 접근
   for(String key : set) {
      System.out.printf("[%s] %s \n", key, map.get(key));
   }
   // 결과값 : [롯데월드] 서울시 송파구 
               [스타필드 하남] 경기도 하남시 
               [학원] 서울시 강남구
}
public void ex3() {
// Map은 언제 사용하면 좋을까?
		
// 1) 한 번에 많은 양의 데이터를 
//    명확하게 구분할 수 있는 형태로 전달해야되는 경우
		
// 2) VO(Value Object) : 값 전달용 객체
//    Vo가 없거나, 있어도 사용 빈도가 낮은 경우
//    Map으로 대체해서 사용
		
   Map<String, Object> s1 = new HashMap<>();
   // Value의 타입이 Object로 제한되어있다.
   // == 어떤 객체든 Value에 들어올 수 있다!
		
   s1.put("grade", 3); // 3(int) -> Integer로 Auto Boxing
   s1.put("ban", 5);
   s1.put("number", 17);
   s1.put("name", "카리나");
   s1.put("gender", 'F');
   s1.put("score", 40);
		
   Set<String> set = s1.keySet(); // key들의 집합
		
   for(String key : set) {
      System.out.printf("[%s]: %s \n", key, s1.get(key));
   }
   // 결과값 : [number]: 17 
               [score]: 40 
               [gender]: F 
               [grade]: 3 
               [name]: 카리나 
               [ban]: 5 
               
   System.out.println("--------------------------------------");
   
   // Map과 VO 비교
   Student s2 = new Student();
   s2.setGrade(2);
   s2.setBan(5);
   s2.setNumber(11);
   s2.setName("장원영");
   s2.setGender('F');
   s2.setScore(70);

   System.out.printf("s1: %d학년 %d반 %d번 %s \n",
      s1.get("grade"),s1.get("ban"),s1.get("number"),s1.get("name"));
   // 결과값 : s1: 3학년 5반 17번 카리나 
		
   System.out.printf("s2: %d학년 %d반 %d번 %s \n",
      s2.getGrade(),s2.getBan(),s2.getNumber(),s2.getName());
   // 결과값 : s2: 2학년 5반 11번 장원영
}
public void ex4() {
   List<Map<String, Object>> list = new ArrayList<>(); 
		
   for(int i=0; i<10; i++) {
   // Map 생성
   Map<String, Object> map = new HashMap<>();
			
   // map에 데이터 추가
   map.put("id", "user0"+i);
   map.put("pw", "pass0"+i);
		
   // map을 List에 추가
   list.add(map);
   }
		
   // for문 종료 시 List에는 10개의 Map 객체가 추가 되어있음
   // ★ List에 저장된 Map에서 key가 "id"인 경우의 value 모두 출력
		
   for(Map<String, Object> temp :list) {
      System.out.println(temp.get("id"));
   }
   // 결과값 : user00
              user01
              user02
              user03
              user04
              user05
              user06
              user07
              user08
              user09
}

 

'Java > 기본 개념' 카테고리의 다른 글

변수(Variable)  (0) 2024.12.16
프로그래밍 기초  (0) 2024.12.16
스레드(Thread)  (0) 2024.11.17
네트워크(Network)  (0) 2024.11.17
입출력 (IO_Input / Output)  (3) 2024.11.17