1. 컬렉션 프레임워크의 핵심 인터페이스 & 요약

  • 컬렉션 : 데이터 그룹
  • 프레임워크 : 표준화된 프로그래밍 방식
  • 컬렉션 프레임워크 : 데이터 그룹을 저장하는 클래스들을 표준화한 설계

데이터를 다루는 데는 크게 3가지 타입이 존재한다.

  1. List : 순서O, 중복O
    • ArrayList, LinkedList, Stack, Vector 등
  2. Set : 순서X, 중복X
    • HashSet, TreeSet 등
  3. Map : Key와 Value의 쌍으로 이루어진 데이터집합. ex) 우편번호, Key는 중복X, Value는 중복O
    • HashMap, TreeMap, Hashtable, Properties 등

요약

컬렉션 특징
ArrayList 배열기반. 순차적 추가삭제 빠름. 접근속도 빠름. 중간에 추가 삭제 느림.
LinkedList 연결기반. 중간에 추가 삭제 빠름. 접근속도 느림. 순차적 추가삭제 상대적으로 느림.
HashMap 배열과 연결이 결합된 상태. 추가, 삭제, 검색, 접근성 모두 뛰어남. 검색에 최고성능.
TreeMap 연결기반. 정렬과 검색에 적합. 검색성능은 HashMap보다 떨어짐
Stack Vector를 상속받아 구현
Queue LinkedList가 Queue인터페이스를 구현

2. ArrayList

  • 가장 많이 사용되는 컬렉션 클래스
  • Vector를 개선한 것
  • 배열의 단점(배열 크기 수정 불가)을 개선하기 위해 만들어졌다. (out of bounds 에러 많이도 보았다.)
  • 자동으로 배열의 크기를 늘려준다 -> 배열에 더 이상 저장할 공간이 없으면 보다 큰 배열을 생성해서 기존 배열에 저장된 내용을 복사하고 저장한다.

사용예

import java.util.*;

class ArrayListEx1{
    public static void main(Stringp[] args){
        ArrayList list1 = new ArrayList(4); // 처음 배열의 크기가 작아도 상관없음
        list.add(new Integer(5)); // 리스트에 추가할때 add메서드 사용.
        list.add(4); // 사실 요 안에 4는 컴파일러가 integer 객체로 바꿔준다. 덕분에 편하게 4만 쓸 수 있음. (AutoBoxing)
        list.add(new Integer(2));
        list.add(new Integer(0));
        list.add(new Integer(1));
        list.add(new Integer(3));

        ArrayList list2 = new ArrayList(list1.subList(1,4)); // 1<= x <4 사이에 존재하는 객체를 반환
        print(list1, list2);

        Collections.sort(list1);
        Collections.sort(list2); // list 오름차순 정렬
        print(list1, list2);

        System.out.println("list1.containsAll(list2):" + list1.containsAll(list2));

        list2.add("B");
        list2.add("C");
        list2.add(3, "A");
        print(list1, list2);

        list2.set(3, "AA");
        print(list1, list2);

        // list1에서 list2와 겹치는 부분 남기고 나머지 삭제
        System.out.println("list1.retainAll(list2):" + list1.retainAll(list2));
        print(list1, list2);

        // list2에서 list1에 포함된 객체 삭제
        for(int i = list2.size()-1; i >= 0; i--){
            if(list1.contains(list2.get(i)))
                list2.remove(i);
        }
        print(list1, list2);
    }

    static void print(ArrayList list1, ArrayList list2) {
        System.outprintln("list1:"+list1);
        System.outprintln("list2:"+list2);
        System.outprintln();
    }
}
  • 과제 : ArrayList의 add 메서드가 내부적으로 어떤 논리로 이루어지길래 자동으로 배열의 크기를 조절할 수 있는 걸까? p.591.

  • 참고 : 배열을 새로만들고 복사하는 과정에서 처리시간이 많이 소요된다. 생성할때 여유있는 크기로 정하자.

3. LinkedList

  • 불연속적으로 존재하는 데이터를 서로 연결한 형태로 구성

  • 비순차적인 데이터 추가 삭제 빠르다.

    • 데이터 추가 : 데이터 생성 1번, 연결 2번이면 끝남
    • 데이터 삭제 : 데이터 연결만 바꾸면 끝.
  • Doubly-LinkedList : 양방향 (Ex : Volume up & down)

  • Doubly-Circular LinkedList : 양방향 + 마지막 요소와 첫번째 요소 연결 (Ex : Channel up & down)

4. Stack과 Queue

  • Stack -> 순차적으로 데이터를 추가 삭제하기 때문에 ArrayList로 구현
    • 저장 push
    • 추출 pop
  • Queue -> 삭제 할 때 첫번째 데이터를 삭제하므로, LinkedList로 구현
    • 저장 offer
    • 추출 poll
import java.util.*;

class StackQueueEx {
    public static void main(String[] args){
        Stack st = new Stack();
        Queue q = new LinkedList(); // Queue인터페이스 구현체 LinkedLIst 사용 p.606 참고

        st.push("0");
        st.push("1");
        st.push("2");

        q.offer("0");
        q.offer("1");
        q.offer("2");

        System.out.println("= Stack =");
        while(!st.empty()){
            System.out.println(st.pop());
        }

        System.out.println("= Queue =");
        while(!q.isEmpty()){
            System.out.println(q.poll());
        }

        // 결과를 예상해보자
    }
}

5. Iterator

  • 컬렉션에 저장된 데이터를 접근하는데 사용되는 표준화된 인터페이스
  • Collection 인터페이스에 정의된 메서드 (즉 List, Set에도 Iterator가 포함되어있다)
  • 요소체크 -> 읽음. 다 읽어오면 재사용 안된다. 다시 얻어와야 한다.
import java.util.*;

class IteratorEx1 {
    public static void main(String[] args){
        Collection list = new ArrayList(); // 다른 컬렉션으로 변경할 땐 여기만 바꾸면된다. ArrayList에만 있는 메서드를 사용하는 게 아니라면 Collection 타입을 쓰는 편이 낫다.

        list.add("1");
        list.add("2");
        list.add("3");
        list.add("4");
        list.add("5");

        Iterator it = list.iterator(); // (참조변수 it을 가지고 list를 접근할거야)

        while(it.hasNext()){ // boolean -> 읽어올 요소가 있으면 true
            Object obj = it.next(); // 다음요소를 읽어온다
            System.out.println(obj);
            // System.out.println(it.next()); 
        }
    }

}

6. Arrays

  • 배열을 다룰 때 유용한 메서드가 있다
  • 특히 배열 복사할 때! 정렬할 때!, 검색할 때!
    • Arrays.copyof()
    • sort()
    • binarySearch()

7. Comparator와 Comparable

  • 정렬방법
    • 기본 오름차순 정렬하려면 Comparable
    • 다른 기준으로 정렬하려면 Comparator 구현
  • Comparator 구현
    • public int compare(Object o1, Object o2) 메서드 만들기
    • compare()의 매개변수가 Object타입이기 때문에 compareTo()를 바로 호출할 수 없으므로 먼저 Comparable로 형변환 해야한다
    • 메서드 안에 정렬기준식 쓴다
import java.util.*;

class ComparatorEx{
    public static void main(String[] args){
        String[] strArr = { "cat", "Dog", "lion", "tiger" };

        Arrays.sort(strArr); // Comparable구현에 의한 정렬
        System.out.println(Arrays.toString(strArr));

        Arrays.sort(strArr, String.CASE_INSENSITIVE_ORDER); // 대소문자 구분안함
        System.out.println(Arrays.toString(strArr));

        Arrays.sort(strArr, new Descending()); // 새로운 정렬 기준. Descending 클래스를 만들고 Comparator 인터페이스 구현
        System.out.println(Arrays.toString(strArr));
    }
}

class Descending implements Comparator{
    public int compare(Object o1, Object o2){
        if(o1 instanceof Comparable && o2 instanceof Comparable){
            Comparable c1 = (Comparable)o1;
            Comparable c2 = (Comparable)o2;
            return c2.compareTo(c1) ; // 역순정렬
        }
        return -1;
    }
}

실행결과

[Dog, cat, lion, tiger]
[cat, Dog, lion, tiger]
[tiger, lion, cat, Dog]

8. HashSet(참고)

9. TreeSet

  • 범위 검색과 정렬에 유리한 컬렉션 클래스
  • Binary Search Tree(이진탐색트리)로 구현
  • 전위, 중위, 후위. 중위순회하면 오름차순 정렬

10. HashMap과 Hashtable

  • HashMap은 Hashtable의 새로운 버전
  • Id, Password처럼 연관된 데이터는 하나의 배열로 다루는 것이 바람직하다.
  • Id와 Password를 하나의 Entry로 저장한다.
  • Id(Key)는 중복이면 안된다.
  • 해싱(Hashing)을 사용하여 많은양의 데이터 검색에 유리

포프킴이 면접으로 Hashtable을 구현해보라는 문제를 종종 낸다고 한다. 이유는 여기 : 포프킴-Hashtable은 프로그래머의 기본기

고로 예제 하나 풀어보자(Hashtable을 구현한 것은 아니고 사용만 한 것)

import java.util.*;

class HashMapEx1{
    public static void main(String[] args){
        HashMap map = new HashMap();
        map.put("myId", "1234"); // Key와 Value를 HashMap에 저장
        map.put("asdf", "1111");
        map.put("asdf", "1234"); // Key가 중복인 경우 덮어씌여진다

        Scanner s = new Scanner(System.in);

        while(true) {
            System.out.println("id와 password를 입력해주세요");
            System.out.print("id :");
            String id = s.nextLine().trim();

            System.out.print("password :");
            String password = s.nextLine().trim();
            System.out.println();

            if(!map.containsKey(id)){
                System.out.println("입력하신 id는 존재하지 않습니다." + " 다시 입력해주세요.");
                continue;
            } else {
                if(!(map.get(id)).equals(password)){
                    System.out.println("비밀번호가 일치하지 않습니다." + " 다시 입력해주세요.");
                } else {
                    System.out.println("id와 비밀번호가 일치합니다.");
                    break;
                }
            }

            
        }
    }
}

참고자료