배열과 Collections Framework

배열은 연관된 데이터를 관리하기 위한 수단이었다. 그런데 배열에는 몇 가지 불편한 점이 있었는데 그 중의 하나가 한번 정해진 배열의 크기를 변경할 수 없다는 점이다. 이러한 불편함은 Collections Framework를 사용하면 줄어든다.

 

아래의 예제를 보자.

 

[배열]

package collection;

public class ArrayListDemo {
    public static void main(String[] args) {
        String[] arrayObj = new String[2];
        arrayObj[0] = "one";
        arrayObj[1] = "two";
        arrayObj[2] = "three";
        for(int i = 0; i < arrayObj.length; i++){
            System.out.println(arrayObj[i]);
        }
    }
}

실행 결과

배열의 크기가 2인데, 3개의 String을 담으려고 시도하다보니 ArrayIndexOutOfBoundsException 에러가 발생했다.

이처럼 배열은 그 크기를 한번 지정하면 크기보다 많은 수의 값을 저장할 수 없다.

 

하지만 ArrayList는 크기를 미리 지정하지 않기 때문에 얼마든지 많은 수의 값을 저장할 수 있다.

 

[Collections Framework]

package collection;

import java.util.*;

public class ArrayListDemo2 {
    public static void main(String[] args) {
        ArrayList al = new ArrayList();
        al.add("one"); //index 0
        al.add("two"); //index 1
        al.add("three"); //index 2
        for(int i = 0; i<al.size(); i++){
            System.out.println(al.get(i));
        }
    }
}

실행 결과

 

package collection;

import java.util.*;

public class ArrayListDemo2 {
    public static void main(String[] args) {
        ArrayList al = new ArrayList();
        //al.add(Object 타입)
        al.add("one"); //Object 데이터 타입으로 저장됨
        al.add("two"); //Object 데이터 타입으로 저장됨
        al.add("three"); //Object 데이터 타입으로 저장됨
        for(int i = 0; i<al.size(); i++){
            String value = (String) al.get(i); //Object → String으로 형변환
            System.out.println(value);
        }
    }
}

add(): Object 타입으로 데이터를 저장한다.

따라서 String 타입의 value에 담고 싶다면 al.get(i)를 String 타입으로 다운캐스팅해야 한다.

 


Generic 도입 - 타입의 안정성 확보

package collection;

import java.util.*;

public class ArrayListDemo2 {
    public static void main(String[] args) {
        ArrayList<String> al = new ArrayList<String>();
        //제네릭을 통해 al에 추가되는 값을 String으로 제한
        al.add("one"); //String 타입으로 저장됨
        al.add("two"); //String 타입으로 저장됨
        al.add("three"); //String 타입으로 저장됨
        for(int i = 0; i<al.size(); i++){
            String value = al.get(i);
            System.out.println(value);
        }
    }
}

 

 


Collections Framework란?

Collections Framework는 '컨테이너'라고도 부른다. 즉, 값을 담은 그릇이라는 의미이다. 그런데 그 값의 성격에 따라 컨테이너의 셩걱이 조금씩 달라진다. 자바에서는 다양한 상황에서 사용할 수 있는 다양한 컨테이너를 제공하는데 이것을 Collections Framework라고 부른다. ArrayList는 그 중의 하나다.

 

Collections Framework의 구성

 

Collection과 Map이라는 최상위 카테고리가 있고, 그 아래에 다양한 컬렉션들이 존재한다.

구체적인 Collections Framework 클래스들을 살펴보자.

 

1. 팀을 구성하려고 한다. 한 명씩만 필요하고
팀원은 디자이너, 프로그래머, DB관리자가 있다.
팀원 목록을 프린트!
중복허용X → Set
2. 냉장고에 어제, 오늘자 우유를 사다 놓았다.
어제 우유의 이름은 덜싱싱우유
오늘 우유의 이름은 싱싱우유
어제의 우유를 먼저 먹었다.
현재 남은 우유의 이름인 싱싱우유를 프린트!
FIFO → Queue
3. 스키대회에서
1등: 박스키, 2등: 송스키, 3등: 김스키, 4등: 정스키
2등 송스키가 반칙하여 탈락했다.
스키대회 시상자 목록을 프린트!
순서 → List
4. 휴대폰 단축키 1번은 엄마, 2번은 아빠,
3번은 친구, 4번은 동생
휴대폰 2번은 누구인지 프린트!
key + value → Map

 


List와 Set의 차이점

List는 중복을 허용하고, Set은 중복을 허용하지 않는다.

 

[HashSet]

package collection;
import java.util.*;
public class SetDemo {
    public static void main(String[] args) {
        HashSet<Integer> A = new HashSet<Integer>();
        A.add(1);
        A.add(2);
        A.add(2);
        A.add(2);
        A.add(2);
        A.add(3);
        
        Iterator it = (Iterator) A.iterator();
        while(it.hasNext()){
            System.out.println(it.next());
        }
    }
}

실행 결과

 

[ArrayList]

package collection;
import java.util.*;
public class SetDemo {
    public static void main(String[] args) {
        ArrayList<Integer> A = new ArrayList<Integer>();
        A.add(1);
        A.add(2);
        A.add(2);
        A.add(2);
        A.add(2);
        A.add(3);

        Iterator it = (Iterator) A.iterator();
        while(it.hasNext()){
            System.out.println(it.next());
        }

실행 결과

 

HashSet: 중복되는 값은 들어가지 않고, 고유한 값들만이 저장되는 특성

1 2 3

 

ArrayList: 입력한 모든 값이 저장됨

1 2 2 2 2 3

 


Set이란?

Set은 한국어로 집합이라는 뜻이다. 여기서의 집합이란 수학의 집합과 같은 의미다. 수학에서의 집합도 순서가 없고 중복되지 않는 특성이 있다는 것이 기억날 것이다. 수학에서 집합은 교집합(intersect), 차집합(difference), 합집합(union)과 같은 연산을 할 수 있었다. Set도 마찬가지다.

 

아래 코드와 같이 3개의 집합 hs1, hs2, hs3이 있다고 하자. h1은 숫자 1,2,3으로 이루어진 집합이고, h2는 3,4,5로 이루어져 있고, h3는 1,2로 구성되어 있다. set의 API를 이용해서 집합 연산을 해보자.

package collection;
import java.util.*;
public class SetDemo {
    public static void main(String[] args) {
        ArrayList<Integer> A = new ArrayList<Integer>();
        A.add(1);
        A.add(2);
        A.add(3);

        HashSet<Integer> B = new HashSet<Integer>();
        B.add(3);
        B.add(4);
        B.add(5);

        HashSet<Integer> C = new HashSet<Integer>();
        C.add(1);
        C.add(2);

        //부분집합
        System.out.println(A.containsAll(B)); //false
        System.out.println(A.containsAll(C)); //true
    }
}

실행 결과

 

부분집합 (subset)

System.out.println(A.containsAll(B)); //false
System.out.println(A.containsAll(C)); //true

 

합집합 (union)

package collection;

import java.util.HashSet;
import java.util.Iterator;
public class SetDemo {
    public static void main(String[] args) {
        HashSet<Integer> A = new HashSet<Integer>();
        A.add(1);
        A.add(2);
        A.add(3);

        HashSet<Integer> B = new HashSet<Integer>();
        B.add(3);
        B.add(4);
        B.add(5);

        HashSet<Integer> C = new HashSet<Integer>();
        C.add(1);
        C.add(2);
        
        //합집합
        A.addAll(B);
        Iterator hi = A.iterator();
        while(hi.hasNext()){
            System.out.println(hi.next());
        }
    }
}

실행 결과

 

교집합 (intersect)

package collection;

import java.util.HashSet;
import java.util.Iterator;
public class SetDemo {
    public static void main(String[] args) {
        HashSet<Integer> A = new HashSet<Integer>();
        A.add(1);
        A.add(2);
        A.add(3);

        HashSet<Integer> B = new HashSet<Integer>();
        B.add(3);
        B.add(4);
        B.add(5);

        HashSet<Integer> C = new HashSet<Integer>();
        C.add(1);
        C.add(2);

        //교집합
        A.retainAll(B); //A와 B에 모두 들어있는 값(3)을 A에 대입해라
        Iterator hi = A.iterator();
        while(hi.hasNext()){
            System.out.println(hi.next());
        }
    }
}

실행 결과

 

차집합 (difference)

package collection;

import java.util.HashSet;
import java.util.Iterator;
public class SetDemo {
    public static void main(String[] args) {
        HashSet<Integer> A = new HashSet<Integer>();
        A.add(1);
        A.add(2);
        A.add(3);

        HashSet<Integer> B = new HashSet<Integer>();
        B.add(3);
        B.add(4);
        B.add(5);

        HashSet<Integer> C = new HashSet<Integer>();
        C.add(1);
        C.add(2);

        //차집합
        A.removeAll(B); //A에 있는 값중에 B에도 있는 값을 제거해라
        Iterator hi = A.iterator();
        while(hi.hasNext()){
            System.out.println(hi.next());
        }
    }
}

실행 결과

 


Collection interface

https://prashantgaurav1.files.wordpress.com/2013/12/java-util-collection.gif

 

 


iterator

* iteration: 반복

컨테이너에 담긴 값들을 하나씩 꺼내서 어떤 처리를 할 수 있도록 역할을 함

 

Iterator api

https://docs.oracle.com/javase/8/docs/api/java/util/Iterator.html

 

Iterator (Java Platform SE 8 )

An iterator over a collection. Iterator takes the place of Enumeration in the Java Collections Framework. Iterators differ from enumerations in two ways: Iterators allow the caller to remove elements from the underlying collection during the iteration with

docs.oracle.com

 

Method Summary

Modifier and Type Method and Description
boolean hasNext()
Returns true if the iteration has more elements.
E next()
Returns the next element in the iteration.

package collection;

import java.util.HashSet;
import java.util.Iterator;
public class SetDemo {
    public static void main(String[] args) {
        HashSet<Integer> A = new HashSet<Integer>();
        A.add(1);
        A.add(2);
        A.add(3);

        Iterator hi = A.iterator();
        while(hi.hasNext()){
            System.out.println(hi.next());
        }
    }
}

실행 결과

 

[진행 과정]

Iterator hi = A.iterator();
while(hi.hasNext()){ 
    System.out.println(hi.next());
    }

Iterator hi = A.iterator(); A집합(1, 2, 3)을 복제한 hi집합(1, 2, 3)이 생김

 

<반복문 진행 과정>

hi집합(1, 2, 3)
hasNext(): hi집합(1, 2, 3)에서 가져올 값이 있는지 확인 = true
hi.next(): hi집합(1, 2, 3)에 들어있는 값 중 하나인 1을 리턴한다. 그 뒤에 hi집합에서 1이 사라진다.
=> hi집합(2,3)
hasNext(): 다음으로 가져올 값이 있는지 확인 = true
hi.next(): hi집합(2,3)에 들어있는 값 중 하나인 2를 리턴한다. 그 뒤에 hi집합에서 2가 사라진다.
=> hi집합(3)
hasNext(): hi집합(3)에서 가져올 값이 있는지 확인 = true
hi.next(): hi집합(3)에 들어있는 값인 3을 리턴한다. 그 뒤에 hi집합에서 3이 사라진다.
=> hi집합(null)
hasNext(): hi집합(null)에서 가져올 값이 있는지 확인 = false
=> 반복문을 벗어난다.

 


Map

Map 컬렉션은 key와 value의 쌍으로 값을 저장하는 컬렉션이다.

List / Set / Map의 차이

 

[HashMap]

package collection;

import java.util.*;

public class MapDemo {
    public static void main(String[] args) {
        HashMap<String, Integer> a = new HashMap<String, Integer>();
        //<key, value>
        a.put("one", 1); //put()은 Map 인터페이스에서만 존재한다.
        a.put("two", 2);
        a.put("three", 3);
        a.put("four", 4);
        System.out.println(a);
        System.out.println(a.get("one")); //1
        System.out.println(a.get("two")); //2
        System.out.println(a.get("three")); //3
        //key는 value를 얻어오기 위한 열쇠
    }
}

실행 결과

 


 

[예제2]

package collection;
import java.util.*;

public class HashMapTest {
    public static void main(String[] args) {
        HashMap<String, Integer> map = new HashMap<>();
        map.put("생년", 1995);
        map.put("나이", 30);
        map.put("용돈", 500000);
        System.out.println(map);
    }
}

실행 결과

 

package collection;
import java.util.*;

public class HashMapTest {
    public static void main(String[] args) {
        HashMap<String, Integer> map = new HashMap<>();
        map.put("생년", 1995);
        map.put("나이", 30);
        map.put("용돈", 500000);
        map.put("용돈", 700000);
        System.out.println(map); //덮어쓰기(overwrite)
    }
}

실행 결과

같은 key값에 다른 value를 넣으면 나중에 넣은 value값으로 덮어쓰기된다.

 

package collection;
import java.util.*;

public class HashMapTest {
    public static void main(String[] args) {
        HashMap<String, Integer> map = new HashMap<>();
        map.put("생년", 1995);
        map.put("나이", 30);
        map.put("용돈", 500000);
        map.put("용돈", 700000);
        System.out.println(map); //덮어쓰기(overwrite)

        System.out.println("map.size(): " + map.size());
        //배열은 length, 컬렉션은 size()
    }
}

배열의 크기는 length를 사용하는 반면, 컬렉션 프레임워크 타입의 크기는 size() 메서드를 사용한다.

 


Map 전체 내용 꺼내기

1. entrySet(): Map의 전체 key와 value를 꺼낸다.
2. keySet(): Map의 전체 key를 꺼낸다.
3. Iterator: hasNext(), next()
4. Collection<V> values()

 

Map.Entry <K, V>

https://docs.oracle.com/javase/8/docs/api/java/util/Map.Entry.html

 

Map.Entry (Java Platform SE 8 )

All Known Implementing Classes: AbstractMap.SimpleEntry, AbstractMap.SimpleImmutableEntry Enclosing interface: Map public static interface Map.Entry A map entry (key-value pair). The Map.entrySet method returns a collection-view of the map, whose elements

docs.oracle.com

Map 인터페이스는 키(Key)와 값(Value)으로 구성된 객체를 저장하는 구조이다. 키와 값으로 구성된 객체를 Entry 객체라고 한다. 즉, Map 인터페이스는 Entry 객체를 저장하는 구조이며, Entry 객체는 Key 객체와 Value 객체로 저장한다.

 

 

1. entrySet()

Set entrySet(): key와 value로 구성된 한 쌍을 Set으로 얻을 수 있음

package collection;
import java.util.*;

public class HashMapTest {
    public static void main(String[] args) {
        HashMap<String, Integer> map = new HashMap<>();
        map.put("생년", 1995);
        map.put("나이", 30);
        map.put("용돈", 700000);

        //entrySet()
        Set <Map.Entry<String, Integer>> set = map.entrySet(); //key값과 value값을 Set으로 가져온다.
        System.out.println(set);
        for (Map.Entry<String, Integer> entry : set) {
            System.out.println("key: " + entry.getKey() + ", value: " + entry.getValue());
        }
    }
}

 

2. keySet()

Set keySet(): key를 Set로 얻을 수 있음

package collection;
import java.util.*;

public class HashMapTest {
    public static void main(String[] args) {
        HashMap<String, Integer> map = new HashMap<>();
        map.put("생년", 1995);
        map.put("나이", 30);
        map.put("용돈", 700000);

        //keySet()
        Set<String> set = map.keySet(); //key값을 Set으로 가져온다.
        System.out.println(set);
        for (String s : set) {
            System.out.println(s + ": " + map.get(s));
        }
    }
}

실행 결과

 

3. Iterator: hasNext(), next()

boolean hasNext(): 복제된 집합에서 가져올 값이 있는지 확인 

next(): 집합에 들어있는 값 중 하나를 리턴, 그 값은 집합에서 사라짐

package collection;
import java.util.*;

public class HashMapTest {
    public static void main(String[] args) {
        HashMap<String, Integer> map = new HashMap<>();
        map.put("생년", 1995);
        map.put("나이", 30);
        map.put("용돈", 700000);

        //iterator: hasNext(), next()
        Set<String> set = map.keySet(); //key값을 Set으로 가져온다.
        Iterator<String> it = set.iterator(); //key값이 들어있는 set을 복제한 it집합(용돈,나이,생년)이 생김
        while(it.hasNext()){ //it집합에서 가져올 값이 있는지 확인
            System.out.println(it.next()); //it집합에 들어있는 값들들 리턴
        }
    }
}

실행 결과

 

4. Collection<V> values()

value값들만 Collection 유형으로 반환한다.

package collection;
import java.util.*;

public class HashMapTest {
    public static void main(String[] args) {
        HashMap<String, Integer> map = new HashMap<>();
        map.put("생년", 1995);
        map.put("나이", 30);
        map.put("용돈", 700000);

        //Collection<V> values()
        System.out.println(map.values());
        Collection<Integer> col = map.values();
        for (Integer value : col) {
            System.out.println("value: " + value);
        }
    }
}

실행 결과

 


Queue

Queue(인터페이스)

  • List 계열
  • 구현한 클래스 LinkedList, PriorityQueue
  • FIFO 구조 (First In First Out)

 

poll(), remove()

Queue의 맨 앞에 있는 요소를 꺼내 삭제하고, 삭제한 요소를 반환하는 메서드

package arraylist;
import java.util.*;

public class QueueTest {
    public static void main(String[] args) {
        Queue<String> q = new LinkedList<>();
        q.add("어제 들어온 우유");
        q.add("오늘 들어온 우유");
        q.add("내일 들어올 우유");
        System.out.println(q);
        System.out.println("-----------------------------------------------");

        //poll(), remove(): Queue의 맨 앞에 있는 요소를 꺼내 삭제하고, 삭제한 요소를 반환
        System.out.println(q.poll() + "를 꺼냈어요.");
        System.out.println("남은 우유: " + q);
        System.out.println(q.remove() + "를 꺼냈어요.");
        System.out.println("남은 우유: " + q);
    }
}

실행 결과

 


Properties

Properties란?

  • Properties는 HashMap의 구버전인 Hashtable을 상속받아 구현한 것으로, Hashtable은 키와 값을 (Object, Object)의 형태로 저장하는 반면, Properties는 (String, String)의 형태로 저장하는 보다 단순화된 컬렉션 클래스이다.
  • 주로 애플리케이션의 환경설정과 관련된 속성을 저장하는 데 사용되며 데이터를 파일로부터 읽고 쓰는 편리한 기능을 제공한다. 간단한 입출력은 Properties를 활용하면 몇 줄의 코드로 쉽게 해결할 수 있다.

 

예제

[예제1]

package arraylist;

import java.util.Properties;

public class PropertiesTest {
    public static void main(String[] args) {
        Properties prop = new Properties();
        //setProperty()
        prop.setProperty("OS", "Windows");
        prop.setProperty("Lang", "Java");
        System.out.println(prop);
        //getProperty()
        System.out.println("사용하는 운영체제: " + prop.getProperty("OS"));
        System.out.println("사용하는 언어: " + prop.getProperty("Lang"));

    }
}

실행 결과

Object setProperty(String key, String value) Properties 객체에 키와 값(value) 저장
String getProperty(String key) key값을 제공하면 해당하는 value를 문자열로 반환함

 

 

[예제2]

java.util에서 제공하는 Properties 객체를 활용하여 .properties 파일을 FileInputStream으로 읽고, load 메서드를 활용하여 해당 파일을 읽을 수 있다.

database.properties 파일

package arraylist;

import java.io.FileInputStream;
import java.io.IOException;
import java.util.Properties;

public class PropertiesTest2 {
    public static void main(String[] args) throws IOException {
        Properties prop = new Properties();

        //파일과 노드 연결
        FileInputStream fis = new FileInputStream("src/arraylist/database.properties");
        prop.load(fis);

        //database.properties 파일을 읽어서 Properties 객체로 옮겨 놓는다
        fis.close();
        System.out.println(prop);

        //DbUser와 DbPwd만 가져와서 출력하기
        System.out.println(prop.getProperty("DbUser"));
        System.out.println(prop.get("DbPwd"));
    }
}

실행 결과

void load (FileInputStream file) 스트림으로 열린 Properties 파일 객체를 로드함
load (FileReader file)

 

+ Recent posts