고래씌

[JAVA] 14-3. 컬렉션(Collection) - Map 본문

JAVA/JAVA 기초

[JAVA] 14-3. 컬렉션(Collection) - Map

고래씌 2023. 10. 25. 16:44

1. Map

▶ 인터페이스 계층구조를 확인해봤을 때 List나 Set 계열은 Collection 인터페이스를 상속받고 있음
ex) 데이터를 추가할 때 전부 동일한 add메소드를 사용

 

▶ 단, Map은 다르다. 데이터 추가시 put메소드를 사용(key + value을 세트로 추가)

 

 

1) Map의 특징

▶ key, value을 한쌍으로 요소를 구성한다.
key를 통해서 value에 접근해 사용
key는 중복을 허용하지 않는다. value는 중복되어도 좋다.

동일한 key로 추가 저장하면, 마지막에 추가한 value로 치환
동일한 key값 여부는 hashCode() 반환값으로 판단한다.

 

 

[표현법]

Map<String, Snack> hm = new HashMap<>();

 Map<K, V> : V value 값으로 Snack 객체만을 저장하겠다라고 선언
                           K key값으로 String자료형 값만을 사용하겠다고 선언

 

 


 

1) put(key, value)

 

■ Snack 클래스

package com.kh.chap03_hashMap.model.vo;

public class Snack {
	
	private String flavor;
	private int calory;
	
	public Snack() {
		
	}

	public Snack(String flavor, int calory) {
		super();
		this.flavor = flavor;
		this.calory = calory;
	}

	public String getFlavor() {
		return flavor;
	}

	public void setFlavor(String flavor) {
		this.flavor = flavor;
	}

	public int getCalory() {
		return calory;
	}

	public void setCalory(int calory) {
		this.calory = calory;
	}

	@Override
	public String toString() {
		return "Snack [flavor=" + flavor + ", calory=" + calory + "]";
	}

}

 

■ Run클래스

package com.kh.chap03_hashMap.run;

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

import com.kh.chap03_hashMap.model.vo.Snack;

public class Run {

	public static void main(String[] args) {
		
		Map<String, Snack> hm = new HashMap<>();
		
		hm.put("다이제", new Snack("초코맛", 1000));
		hm.put("칸초", new Snack("초코맛", 600));
		hm.put("포카칩", new Snack("짠맛", 500));
		hm.put("새우깡", new Snack("짠맛", 500));
//		hm.put(1, new Snack());   // 에러 발생. String자료형만 넣기로 했는데 int자료형을 넣어서 에러발생
		
		System.out.println(hm);
		
		
		// 중복된 key값으로 저장시 value값은 마지막에 등록한 값으로 치환됨
		hm.put("새우깡", new Snack("짠맛", 400));
		
		System.out.println(hm);
		
	}

}

☞ hm.put(1, new Snack());   // 에러 발생. String자료형만 넣기로 했는데 int자료형을 넣어서 에러발생

☞ 중복된 key 값으로 저장시 valuer 값이 마지막에 등록한 값으로 치환된 것을 확인

 

 

2) get(Object key) : V  => 컬렉션에서 해당 키값의 value값을 돌려주는 메소드

package com.kh.chap03_hashMap.run;

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

import com.kh.chap03_hashMap.model.vo.Snack;

public class Run {

	public static void main(String[] args) {
		
		Map<String, Snack> hm = new HashMap<>();
		
		hm.put("다이제", new Snack("초코맛", 1000));
		hm.put("칸초", new Snack("초코맛", 600));
		hm.put("포카칩", new Snack("짠맛", 500));
		hm.put("새우깡", new Snack("짠맛", 500));
	

		hm.put("새우깡", new Snack("짠맛", 400));
		
		
		System.out.println(hm.get("다이제"));
	}

}

 

 

3) size() => 컬렉션에 담겨있는 개수

        System.out.println("size : " +hm.size());

 

4) replace(K key, V value)  => 컬렉션에 해당 key값을 찾아서 새로 전달된 value으로 변경시켜주는 메소드

		hm.replace("포카칩", new Snack("트리플치즈", 1000));  
		
		System.out.println(hm);

☞ replace -> put으로 한다면 똑같은 key 값이 있다면 변경이 되지만, 
☞  replace의 경우, key이 다른 것을 입력했다면 추가가 안되지만, put은 추가됨

 

 

5) remove(Object key) : 컬렉션에서 해당 key 값을 찾아서 지워주는 메소드

		hm.remove("새우깡");
		System.out.println(hm);

☞ 새우깡 key값과 value 값이 삭제됨

 

 


2. 순차적으로 HashMap에 담겨있는 값들에 접근하고자 할 때?

▶ keySet() : key값들을 set에 담아서 반환.["다이제","포카칩","칸초","새우깡"]
 entrySet() : key, value 한쌍을 set에 담아서 반환 ["다이제"=Snack, "포카칩"=Snack, ...]

 

※  향상된 반복문 사용불가 => 향상된 반복문에는 배열, Collection 인터페이스를 구현한 클래스만 들어올 수 있음
☞ for( ? : hm)  =>   X

※   List와 Map은 ★서로 다른 계열!!!★ 이기 때문에 ArrayList에 담아줄수가 없음
 new ArrayList(hm);   =>   X

 

iterator()는 Collection의 추상메소드이기 때문에 사용 불가

 

=> 따라서 반복문을 돌리기 위해서는 keySet 혹은 entrySet을 통해 Set계열로 변환을 한 후 반복해야함

 

 

1) keySet()을 이용하는 방법

① hashMap의 Key 값들만 모아서 Set에 담아서 반환해줌

		Set<String> keySet = hm.keySet();  // ["다이제","포카칩","칸초"]

 

② 1번과정에서 작업된 keySet을 Iterator에 담기

		//    keySet.iterator()
		Iterator<String> itKey = keySet.iterator();
		
		Iterator<String> itKey2 = hm.keySet().iterator();  // 1번 과정 생략

 

 

③ 반복자에 담긴 것들을 순차적으로 뽑기

		while(itKey.hasNext()) {
			String key = itKey.next();  
			Snack value = hm.get(key);
			System.out.println("key : " + key);
			System.out.println("value : " + value);
		}

 

2) entrySet()을 이용하는 방법

① hm에 있는 key + value 값을 모두 묶어서 Set에 담은 후 반환

		Iterator itEntry = hm.entrySet().iterator();

 

② 반복문을 활용해서 순차적으로 값을 출력

		while(itEntry.hasNext()) {
			
			// itEntry.next()는 Object로 되어 있기 때문에 Entry로 다운캐스팅을 해주어야 함
			Entry entry = (Entry)itEntry.next();
			System.out.println("key : " + entry.getKey());
			System.out.println("value : " + entry.getValue());
		}

 

☞ itEntry.next()는 Object로 되어 있기 때문에 Entry로 다운캐스팅을 해주어야 함

 

 


3. Properties

▶ Map 계열 => key, value 세트로 저장

단, Porperties의 특징은 key, value을 모두 String으로 제한함.

파일 입출력 메소드를 지원함

설정정보를 표현하는데 있어 최적의 형태를 가지고 있음

 

Properties prop = new Properties();

Q. prop에 String자료형이 아닌 값을 추가하게 될 경우?

=> Map계열 구현클래스이기 때문에 put메소드를 통해 key+value 추가 가능

 

package com.kh.chap04_Properties.run;

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

import com.kh.chap03_hashMap.model.vo.Snack;

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

		prop.put("다이제", new Snack("초코", 1300));
		
		System.out.println(prop);
		System.out.println(prop.get("다이제"));
		
	}

}

 

 

☞ 출력은 잘 되는 것을 확인.

Properties를 사용하는 경우는 Properties 내부의 key값 value 값들을 묶어서 파일로 기록하거나, 기록된 내용을 읽어들일때만 사용됨.

이때 기록하고자 하는 파일에 문자열이 아닌 값이 존재하는 경우 기록 불가능

 

        Properties prop = new Properties();

        prop.put("다이제", new Snack("초코", 1300));

        System.out.println(prop);
        System.out.println(prop.get("다이제"));

        try {
            prop.store(new FileOutputStream("test.properties"), "Properties test");
        } catch (IOException e) {
            e.printStackTrace();
        }

오류 발생

 

 

1) setProperty(String key, String value)

=> Properties에 값을 추가할 때는 put를 잘 사용안함
=> 잘못된 자료형의 값을 추가할 수 있기 때문

 

		Properties prop = new Properties();

		prop.setProperty("List", "ArrayList, Vector, LinkedList");
		prop.setProperty("Set", "HashSet, TreeSet");
		prop.setProperty("Map", "HashMap, Properties");
		prop.setProperty("Map", "TreeMap");
		
		System.out.println(prop);   // 저장순서 유지 X, key값 중복 허용하지 않음

☞ 저장순서 유지 X, key값 중복 허용하지 않음

 

 

2) getProperty(String key)

		System.out.println(prop.getProperty("Set"));

 

 

3) store( OutputStream os, String comments ) Properties 에 담긴 key-value값들을 파일로 출력

: Properties 객체 내부의 데이터를 기록하는 방법

 

		prop.setProperty("List", "ArrayList, Vector, LinkedList");
		prop.setProperty("Set", "HashSet, TreeSet");
		prop.setProperty("Map", "HashMap, Properties");
		prop.setProperty("Map", "TreeMap");
		
		
		// Properties 객체 내부의 데이터를 기록하는 방법
		// 3. store( OutputStream os, String comments ) Properties 에 담긴 key-value값들을 파일로 출력
		
		try {
			prop.store(new FileOutputStream("test.properties"), "Properties test 1");
		} catch (IOException e) {
			e.printStackTrace();
		}

 

 

4) storeToXML(OutputStream os, String comments) - xml문서에 출력

        prop.setProperty("List", "ArrayList, Vector, LinkedList");
        prop.setProperty("Set", "HashSet, TreeSet");
        prop.setProperty("Map", "HashMap, Properties");
        prop.setProperty("Map", "TreeMap");

        try {
            prop.storeToXML(new FileOutputStream("test.xml"), "xml test 1");
        } catch (IOException e) {
            e.printStackTrace();
        }

test.xml의 Design
test.xml의 Source

 

 

5) load(InputStream is)

: 파일 내부를 읽어오는 것

package com.kh.chap04_Properties.run;

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

public class PropertiesRun2 {

	public static void main(String[] args) {

		Properties prop = new Properties();
		
		System.out.println("읽기 전 : " + prop);
		try {
			// 5. load(InputStream is)
			prop.load(new FileInputStream("test.xml"));

		} catch (IOException e) {
			e.printStackTrace();
		}
		
		System.out.println("읽은 후 " + prop);

	}

}

 

 

6) loadFromXml(InputSteam is) : xml형태의 데이터를 읽어들일때 사용

package com.kh.chap04_Properties.run;

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

public class PropertiesRun2 {

	public static void main(String[] args) {

		Properties prop = new Properties();
		
		System.out.println("읽기 전 : " + prop);
		try {			
			// 6. loadFromXml(InputSteam is) : xml형태의 데이터를 읽어들일때 사용
			prop.loadFromXML(new FileInputStream("test.xml"));
            
		} catch (IOException e) {
			e.printStackTrace();
		}
		
		System.out.println("읽은 후 " + prop);

	}

}

 

 

7) 요소 가져오기

: key 값을 넣으면 그 안에 value 값이 출력됨

package com.kh.chap04_Properties.run;

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

public class PropertiesRun2 {

	public static void main(String[] args) {

        Properties prop = new Properties();	

        try {
            // 5. load(InputStream is)
        //			prop.load(new FileInputStream("test.xml"));

            // 6. loadFromXml(InputSteam is) : xml형태의 데이터를 읽어들일때 사용
            prop.loadFromXML(new FileInputStream("test.xml"));
        } catch (IOException e) {
            e.printStackTrace();
        }


        // 1. 요소 가져오기
        String map = prop.getProperty("Set");   // 대소문자 구별함

        System.out.println(map);

    }

}

☞ 만약 요소를 가져올 때 Set이 아닌 "set"을 넣어준다면 null 이 출력됨. => 대소문자 구별

 

 

 

※ 정리

 .properties 사용하는 경우는  

해당 프로그램이 기본적으로 가져야할 설정정보들을 .properties 확장자 문서로 저장해두면 key값, value값 모두 문자열로 이루어져있어서 개발자가 아닌 일반관리자가 문서를 다루기에 편하다.
개발자와 일반관리자가 협업을 하기에 좋은 도구
jdbc시간 이후에 다시 한번 사용할 예정

 


.xml 사용하는 경우
db에서 실행할 쿼리문을 기록할 때 사용할 예정이며, 그 외에도 다른 프로그래밍 언어와 호환성이 좋기때문에 가장 보편적으로 사용되는 파일 형태임