컬렉션 (Collection)

배지원·2022년 10월 4일
0

JAVA

목록 보기
24/32
  • 컬렉션 : 여러 객체를 모아 놓은 것
  • 프레임웍 : 표준화, 정형화된 체계적인 프로그래밍 방식

1. 컬렉션 프레임웍

  • 컬렉션을 다루기 위한 표준화된 프로그래밍 방식
  • 컬렉션을 쉽고 편리하게 다룰 수 있는 다양한 클래스를 제공
  • java.util패키지에 포함

핵심 인터페이스

인터페이스특징
List순서가 있는 데이터의 집합. 데이터의 중복을 허용한다.(순서 o, 중복 o)
구현 클래스 : ArrayList, LinkedList, Stack, Vector 등
Set순서를 유지하지 않는 데이터의 집합. 데이터의 중복을 허용하지 않는다.(순서 x, 중복 x)
구현 클래스 : HashSet, TreeSet 등
Map키와 값의 쌍으로 이루어진 데이터의 집합, 순서는 유지되지 않으며, 키는 중복을 허용하지 않고, 값은 중복을 허용한다.
(순서 x, 키(아이디)중복 x, 값(비밀번호) 중복 o
구현 클래스 : HashMap, TreeMap, Hashtable, Properties 등

Collection(List, Set 부모클래스)인터페이스의 메서드

(1) List 인터페이스(순서 o, 중복 o)

  • 종류 : ArrayList, LinkedList

① ArrayList

  • 기존의 Vector를 개선한 것으로 구현원리와 기능적으로 동일
  • 데이터의 저장공간으로 배열을 사용한다.

메서드 실습

public class ArrayListTest {
    public static void main(String[] args) {
        ArrayList list1 = new ArrayList(10);        // ArrayList 크기 선언
        list1.add(new Integer(5));      // ArrayList는 객체만 저장가능
        list1.add(4);                         // 컴파일러가 자동으로 autoboxing 해줌
        list1.add(2);
        list1.add(0);
        list1.add(1);
        list1.add(3);

        ArrayList list2 = new ArrayList((list1.subList(1,4)));  // index 1<= x <4 사이의 값 반환
        print(list1,list2);

        // 결과 : list1 :[5, 4, 2, 0, 1, 3]
        //       list2 :[4, 2, 0]


        // Collection은 인터페이스, Collections는 클래스
        Collections.sort(list1);        // list1,list2를 정령한다.
        print(list1,list2);

        // 결과 : list1 :[0, 1, 2, 3, 4, 5]

        System.out.println("list1.containsAll(list2):"+list1.containsAll(list2));   // list1이 list2를 포함하고 있는가
                                                                                    // true 출력
        list2.add("B");
        list2.add("C");
        list2.add(3,"A");   // 원하는 자리에 값을 넣을 수 있음(그 뒤에 값들은 한칸씩 밀림)
        print(list1,list2);

        // 결과 : list1 :[0, 1, 2, 3, 4, 5]
        //       list2 :[4, 2, 0, A, B, C]

        list2.set(3,"AA");      // 값 변경
        print(list1,list2);

        //       list2 :[4, 2, 0, AA, B, C]

        list1.add(0,"1");       // 현재 ArrayList배열안 값 = ["1",0,1,2,3,4,5] index[0]번과 index[2]번의 1은 다름
        System.out.println("index =" + list1.indexOf("1"));
        System.out.println("index =" + list1.indexOf(1));
        print(list1,list2);
        // 결과 : index = 0
        //       index = 2

        list1.remove(0);    // [0,1,2,3,4,5]    index를 통한 자리값 삭제
        list1.remove(new Integer(1));   // [0,2,3,4,5]      // 객체를 통한 값 삭제
        print(list1,list2);
        
    }
    static void print(ArrayList list1, ArrayList list2){
        System.out.println("list1 :"+list1);
        System.out.println("list2 :"+list2);
        System.out.println();
    }
}

ArrayList에 저장된 객체(index(2))의 삭제 과정
(1) index(2)보다 아래에 있는 index의 값을 한칸씩 위로 올려 덮어 씌움 index(3), index(4)를 한칸씩 위로 덮어씌움
(2) 그럼 기존에 index(4)에 남아있는 값이 있을텐데 이 값을 null로 바꿈
(3) 그 후 원래 인덱스 값이 5였는데 그값을 -1하여 4로 줄임
(4) 따라서 for문 사용하여 여러개의 값을 지울때는 0부터가 아닌 맨 아래부터 진행해야 빠르고 깔끔하게 삭제됨

for(int i =list.size()-1; i>=0; i--){
	list.remove(i);
}

※ 객체 삽입과정은 이와 반대로 진행

② LinkedList

(1) 일반 LinkedList

  • 일반 배열의 단점(크기변경 불가, 데이터 추가 및 삭제에 시간 많이 소요)들을 보완하고자 LinkedList가 고안됨
  • 배열과 달리 LinkedList는 불연속적으로 존재하는 데이터를 연결
  • 위의 그림처럼 자신의 값과 다음 값을 저장하고 있는 주소값을 저장함(저장하는 공간 = 노드)
class Node{
	Node next;		// 다음 노드 주소	 ex) 0x300
    Object obj		// 자신의 값            0
}
  • 값 삭제시 다음 노드주소만을 바꿔주면 됨 0x350 => 0x380 으로 바꾼것 처럼
  • 하지만 기존 배열과 달리 원하는 index로 한번에 갈 수가 없음 즉, 0x400 노드를 가기 위해서는 순차적으로 0x200 -> 0x300 -> 0x380 -> 0x400으로 가야하는 데이터 접근성이 나쁨
    따라서 이를 보완하고자 이중 연결 리스트가 생김

(2) 이중 LinkedList

  • 노드끼리 앞뒤로 이동할 수 있도록 함(접근성 향상)
class Node{
	Node next;			// 다음 노드 주소
    Node previous;		// 이전 노드 주소
    Object obj;			// 현재 값
}

(3) 원형 연결 리스트

  • 끝에서 처음으로, 혹은 처음에서 끝으로 이동할 수 있음

③ ArrayList VS LinkedList

(1) 순차적으로 데이터를 추가/삭제 = ArrayList 빠름
(2) 비순차적으로 데이터를 추가/삭제 = LinkedList 빠름
(3) 접근시간 = ArrayList 빠름

(2) Set 인터페이스(순서 x, 중복 x)

  • 저장 순서가 없어 저장할 때의 순서대로 출력할 수 없음
  • 중복을 허용하지 않음(중복 값 들어오면 알아서 중복을 제거함)
  • Collection 메서드와 종류 같음

① HashSet

  • 저장 순서를 유지하지 않음(유지할려면 LinkedHashSet 사용)
  • 인덱스 없음
  • HashMap과 달리 중복을 허용하지 않음
HashSet<Integer> set = new HashSet<Integer>(); // HashSet 초기화
set.add(1);									   // HashSet 값 추가
set.add(2);
set.remove(1);			// HashSet 값 1 삭제(HashSet은 인덱스가 없기 때문에 값이 사라짐(1 삭제)	
set.size();										// 사이즈 구함 (사이즈 : 1)
set.clear();								   // 전부 삭제

HashSet와 LinkedHashSet 차이점

  • HashSet은 중복을 제거해준다는 장점이 있지만 저장 순서를 지켜주지 않음 예를 들어 [1,2,3,4]를 넣고 싶어 1부터 4까지 순서대로 set에 넣을때 set에는 1부터 4까지 순서대로 저장이 되지 않을 수 있다.
  • 따라서 이를 보완하고자 사용하는 것이 LinkedHashSet으로 입력받는 순서대로 저장시켜준다.

(1) 실습1. 중복 데이터 판별

import java.util.HashSet;
import java.util.Set;

public class SetExercise {
    public static void main(String[] args) {
        Set<String> set1 = new HashSet<>();
        set1.add("김경록");
        set1.add("김경록"); //중복으로 들어가지 않음

        Set<Integer> setInteger = new HashSet<>();
        setInteger.add(1);
        setInteger.add(1);			// 중복으로 들어가지 않음
        setInteger.add(2);
        setInteger.add(2);			// 중복으로 들어가지 않음

        System.out.println(setInteger);
    }
}

(2) 실습2. 임의의 숫자 50개 생성수 중복 제거

- 숫자 생성을 위한 인터페이스
    public interface NumberGenerator {
        int generate(int num); //숫자를 생성하는 메소드
    }
- 숫자 생성을 위한 인터페이스 상속
public class RandomNuberGenerator implements NumberGenerator{
    @Override
    public int generate(int num) {
        return (int)(Math.random()*num);
        //num 미만의 랜덤한 숫자를 생성하여 리턴한다.
    }
}
- 메인 메서드
import java.util.HashSet;
import java.util.Set;

public class RndNumbersWithoutDuplicated {
    public static void main(String[] args) {
        RandomNuberGenerator randomNuberGenerator = new RandomNuberGenerator();
        HashSet<Integer> numbers = new HashSet<>();
        for(int i=0;i<50;i++){
            int r= randomNuberGenerator.generate(10); 
            numbers.add(r); //값이 중복된다면 또다시 저장하지 않는다.

        }
        System.out.println(numbers);
        System.out.println(numbers.size());
    }
}

(3) 실습3. A~Z중 임의의 알파벳을 50개 생성후 중복 제거

- 인터페이스
public interface Generator {
    char generate(); 				
}												
- 인터페이스 상속
public class AlphabetGenerator implements Generator {

    @Override
    public char generate() {
        char c = (char) ( Math.random()*26+65);
        return c;
    }
}
- 메인 메서드
import java.util.HashSet;

public class RandomAlphabet {
    public static void main(String[] args) {
        AlphabetGenerator alphabetGenerator = new AlphabetGenerator();
        HashSet<Character> alphabets = new HashSet<>();
        for(int i=0;i<50;i++){
            char r= alphabetGenerator.generate();
            alphabets.add(r);

        }
        System.out.println(alphabets);
        System.out.println(alphabets.size());
    }
}

(4) 실습4. 다른 클래스의 통한 값 추가

  • 다른 클래스에서 객체를 생성하여 값을 Set 안에 넣을때는 같은 값이라도 주소가 다르기 때문에 다른 값이라 판단하여 중복제거를 하지 않음.
  • 따라서 이를 방지하기 위해 클래스안에서 hash, equals 메서드를 통해 오버라이딩하여 비교를 해줘야함
import java.util.HashSet;
import java.util.Objects;


class Person{
    String name;
    int age;
    
    // 비교를 위한 오버라이딩
    @Override
    public boolean equals(Object o) {
        if(!(o instanceof Person)) return false;

        Person person = (Person) o;
        // 나 자신(this)의 이름과 나이를 p와 비교
        return this.name.equals(person.name) && this.age == person.age;
    }

    @Override
    public int hashCode() {
        return Objects.hash(name, age);     // 클래스의 인스턴스 변수를 전부 넣어줌
    }
    // --- 오버라이딩 여기까지 ---
    
    Person(String name,int age){
        this.name = name;
        this.age = age;
    }

    public String toString(){
        return name+" : "+age;
    }
}


public class HashSetTest {
    public static void main(String[] args) {
        HashSet set = new HashSet();

        set.add("abc");
        set.add("abc");
        
        // 객체를 생성하여 Set안에 넣을때는 객체의 주소가 다르기 때문에 같은 내용이 중복되서 들어감
        // 따라서 이를 방지하기 위해 객체의 클래스 안에서 hashcode와 equals를 통해 오버라이딩을 해줘 중복방지를 함
        
        set.add(new Person("David",10));
        set.add(new Person("David",10));

        System.out.println(set);
    }
}

② TreeSet

  • 데이터들이 오름차순으로 정렬된다.
  • 이진 탐색 트리 구조
  • 추가,삭제 시간이 조금 걸리지만 정렬, 범위 검색에는 유리

기본 예제

import java.util.Set;
import java.util.TreeSet;

public class TreeSetTest {
    public static void main(String[] args) {
        Set set = new TreeSet();            // 따로 정렬해줄 필요 없음

        for(int i =0; set.size()<6; i++){
            int num = (int)(Math.random()*45)+1;
            set.add(num);
        }

        System.out.println(set);
    }
}

--- 결과 ---
[5, 8, 20, 35, 38, 42]

범위 검색 예제

import java.util.TreeSet;

public class TreeSetTest2 {
    public static void main(String[] args) {
        TreeSet set = new TreeSet();
        int[] score = {80,95,50,35,45,65,10,100};

        for(int i =0; i<score.length; i++)
            set.add(score[i]);

        System.out.println("50보다도 작은 값 :"+set.headSet(50));
        System.out.println("50보다도 큰 값 :"+set.tailSet(50));
        System.out.println("40과 80사이의 값 :"+set.subSet(40,80));
    }
}
--- 결과 ---
50보다도 작은 값 :[10, 35, 45]
50보다도 큰 값 :[50, 65, 80, 95, 100]
4080사이의 값 :[45, 50, 65]

2. Map 인터페이스(순서 x, 중복(키x, 값o))

  • 값은 중복될 수 있지만, 키는 중복될 수 없음(기존의 키로 다시 저장하면 기존의 값은 사라지고 새로운 값으로 저장됨)
  • null값도 저장 가능
  • Map구조(Key, Value);
  • 종류 : HashMap, TreeMap

(1) HashMap

  • 해싱 기법으로 데이터를 저장, 데이터가 많아도 검색이 빠르다
  • Map인터페이스를 구현한 대표적인 컬렉션 클래스
  • 순서를 유지하려면 LinkedHashMap클래스를 사용하면 된다.

(1) TreeMap

  • 범위 검색과 정렬에 유리한 컬렉션 클래스(TreeSet과 같은 기능을 한다)
  • HashMap보다 데이터 추가, 삭제에 시간이 더 걸림
Map(String, Integer> map = new HashMap<>();	// HashMap<타입,타입>  선언
map.put("홍길동",1);			// map에 값 넣기(key,value)		{홍길동=1}
map.put("이순신",2);			// {이순신=2}
map.remove("홍길동");			// 홍길동이란 키값을 가진 데이터 삭제
map.size();					  // 1	

(1) 실습1. 입력받은 문자열중 알파벳 개수 세기

import java.util.HashMap;
import java.util.Map;

public class AlphabetCnt {

    public static void main(String[] args) {
        String s1 = "abbccceefgh";
        String upper = s1.toUpperCase();    // 모든 문자 대문자로 변환

        Map<Character,Integer> map = new HashMap<>();

        for(char c = 'A'; c<='Z'; c++){     // A~Z까지 비교
            int count = 0;                  
            for(int i=0; i<upper.length(); i++){
                char s = upper.charAt(i);   // 입력한 문자열 문자로 변환
                if(isAlphabet(s)){          // 입력받은 문자가 알파벳이라면
                    if(c == s){             // 현재 바깥 for문에서 A문자를 돌리는 중일때 
                        count++;            // A문자와 입력받은 문자가 같을때 카운트
                    }
                }
            }
            map.put(c,count);
        }
        System.out.println(map);
    }

    public static boolean isAlphabet(char c){
        return ('A'<= c && c<='Z');
    }
}

(2) 로그인 예제

import java.util.HashMap;
import java.util.Map;
import java.util.Scanner;

public class HashMapTest {
    public static void main(String[] args) {
        Map<String,String> map = new HashMap();

        map.put("abc","1234");
        map.put("hello","5678");
        map.put("abc","123");     // 기존의 데이터 덮어 씌움

        Scanner scan = new Scanner(System.in);


        while(true){
            System.out.println("id와 pw를 입력해주세요.");
            System.out.print("id :");
            String id = scan.nextLine().trim();     // 공백을 제거해줌 "1234  " => "1234"

            if(!map.containsKey(id)){               // 입력받은 id가 map에 저장되어 있는 키와 다를때
                System.out.println("입력한 id는 존재하지 않습니다.");
                continue;                           // while문 처음으로 이동
            }

            System.out.print("pw :");
            String pw = scan.nextLine().trim();

            if(!(map.get(id).equals(pw))){
                System.out.println("비밀번화가 일치하지 않습니다. 다시 입력해주세요:");
            }else{
                System.out.println("로그인되었습니다.");
                break;
            }
        }
    }
}

3. Collections

  • 컬렉션을 위한 메서드(static)를 제공
  • 컬렉션 채우기, 복사, 정렬, 검색 - fill( ), copy( ), sort( ), binarySearch( )등
  • 컬렉션의 동기화 - synchronizedXXX( )
    static Collection synchronuzedCollection(Collection c)
    static List synchronuzedList(List list)
    static Set synchronuzedSet(Set set)
    static Map synchronuzedMap(Map map)
    static SortedSet synchronuzedSortedSet(SortedSet s)
    --
    List syncList = Collections.synchronuzedList(new ArrayList(...));
     (동기화된 리스트)                           (동기화되지 않은 리스트)
  • 변경불가(readOnly) 컬렉션 만들기 - unmodifiableXXX( )
       static Collection unmodifiableCollection(Collection c)
       static List unmodifiableList(List list)
       static Set unmodifiableSet(Set set)
       static Map unmodifiableMap(Map map)
       static NavigableSet unmodifiableSortedSet(NavigableSet s)
       static SortedSet unmodifiableMap(SortedSet s)
       static NavigableMap unmodifiableMap(NavigableMap m)
       static SortedMap unmodifiableMap(SortedMap m)
  • 싱글톤(객체 1개만 사용할 수 있는) 컬렉션 만들기 - singletonXXX( )
    static List singleTonList(Object o)
    static Set singleTon(Object o)		// singleTonSet 아님
    static Map singleTonMap(Object key,Object value)
  • 한 종류의 객체(한가지 타입)만 저장하는 컬렉션 만들기 - checkedXXX( )
      static Collection checkedCollection(Collection c, Class type)
      static List checkedList(List list, Class type)
      static Set checkedSet(Set set, Class type)
      static Map checkedMap(Map map, Class keytype, Class valuetype)

Collections 메서드 실습

       List list = new ArrayList<>();
       System.out.println(list);

       // 리스트에 값 대입
       addAll(list,1,2,3,4,5);   // 원래는 Collections.addAll()인데 import를 통해 Collections.* 하여 생략가능
       System.out.println(list);       // [1,2,3,4,5]

       // 오른쪽으로 값 2번 이동
       rotate(list,2);     // [1,2,3,4,5] -> [5,1,2,3,4] -> [4,5,1,2,3]

       // 0번째와 2번째 자리 값 변경
       swap(list,0,2);        // [1,5,4,2,3]

       // 랜덤으로 자리 섞음
       shuffle(list);              // [2,4,5,1,3]

       // 역순으로 정렬
       sort(list,reverseOrder());  // [5,4,3,2,1]
       sort(list);                 // [1,2,3,4,5]

       int idx = binarySearch(list,3); // 3이 저장된 인덱스값 반환 idx=2

       // 최대,최소값 구하기
       max(list);  // 5
       min(list);  // 1
       max(list,reverseOrder());  // 뒤에서 제일 큰값 1 (min과 같음)

       fill(list,9);       // 전부 9로 채움 [9,9,9,9,9]

       // list와 같은 크기의 새로운 list를 생성하고 2로 채운다. 단, 결과는 변경불가
       List newlist = nCopies(list.size(),2);  // [2,2,2,2,2]

       // 2개를 비교하여 공통요소가 없으면 true 출력
       disjoint(list,newlist);     // true

       copy(list,newlist);         // list안의 값에 newlist값을 복사해서 대입

       disjoint(list,newlist);     // false

       replaceAll(list,2,1);   // list안 2의 값을 1로 바꿈  [1,1,1,1,1]
profile
Web Developer

0개의 댓글