본문 바로가기
Backend/Java

[자바의 신] 24장

by unknownomad 2022. 8. 9.

24장 - 자바랭 다음으로 많이 쓰는 애들은 컬렉션 ― Part3 (Map)


Map

  • 모든 데이터는 키와 값이 존재
  • 키 없이 값만 저장 불가
  • 값 없이 키만 저장 불가
  • 키는 해당 Map에서 고유해야
  • 값은 Map에서 중복이어도 상관 x
  • 자바의 Map은 키와 값이 1:1로 저장됨

 

Map 인터페이스에 선언된 메서드

리턴 타입 메서드 이름 및 매개 변수 설명
V put(K key, V value) 첫 번째 매개 변수인 키를 갖는, 두 번째 매개 변수인 값을 갖는 데이터 저장
void putAll(Map<? extends K, ? extends V> m) 매개 변수로 넘어온 Map의 모든 데이터 저장
V get(Object key) 매개 변수로 넘어온 키에 해당하는 값 넘겨줌
V remove(Object key) 매개 변수로 넘어온 키에 해당하는 값 넘겨주며, 해당 키와 값은 Map에서 삭제
Set<K> keySet() 키의 목록을 Set 타입으로 리턴
Collection<V> values() 값의 목록을 Collection 타입으로 리턴
Set<Map.Entry<K,V>> entrySet() Map 안에 Entry라는 타입의 Set 리턴
int size() Map 크기 리턴
void clear() Map 내용 삭제

 

Map의 핵심 메서드

put() get() remove()
Map에 데이터 넣음 데이터 확인 데이터 삭제

 

Map 구현한 주요 클래스

Map 인터페이스 Hashtable 클래스
컬렉션 뷰(Collection view) 통해 데이터 처리
키-값 쌍으로 데이터 순환하여 처리 가능
이터레이션 처리 도중 데이터 삭제하는 안전한 방법 제공
Map 인터페이스 구현함
Enumeration 객체 통해 데이터 처리
키-값 쌍으로 데이터 순환하여 처리 불가
이터레이션 처리 도중 안전한 데이터 삭제 기능 제공 x

 

HashMap vs Hashtable

기능 HashMap Hashtable
키나 값에 null 저장 가능 여부 가능 불가능
여러 쓰레드 안전 여부 불가능 가능

 

Map - Thread safe

  • Hashtable 제외한 Map으로 끝나는 클래스들을 여러 쓰레드에서 동시에 접근해 처리하려면
Map m = Collections.synchronizedMap(new HashMap(...));
Hashtable, Vector 그 외 대부분 Collection 관련 클래스
클래드가 쓰레드에 안전하게 개발됨 위와 같이 처리하거나
이름에 Concurrent 포함돼야 쓰레드에 안전하게 사용 가능
ex) ConcurrentHashMap, CopyOnWriteArrayList

 

HashMap 상속 관계

java.lang.Object
    java.util.AbstractMap<K,V>
        java.util.HashMap<K,V>

 

HashMap이 구현한 인터페이스

인터페이스 용도
Serializable 원격으로 객체 전송 및 파일에 저장할 수 있음을 지정
Cloneable Object 클래스의 clone() 메서드가 제대로 수행될 수 있음을 지정 = 복제 가능한 객체임을 의미
Map<E> Map의 기본 메서드 지정

 

HashMap 클래스의 객체 생성 위한 생성자

생성자 설명
HashMap() 16개의 저장 공간 갖는 HashMap 객체 생성
HashMap(int initialCapacity) 매개 변수만큼의 저장 공간 갖는 HashMap 객체 생성
HashMap(int initialCapacity, float loadFactor) 첫 매개 변수의 저장 공간을 갖고, 두 번째 매개 변수의 로드 팩터를 갖는 HashMap 객체 생성
HashMap(Map<? extends K, ? extends V> m) 매개 변수로 넘어온 Map 구현한 객체에 있는 데이터를 갖는 HashMap 객체 생성
  • HashMap에 담을 데이터 개수 많을 땐 초기 크기 정해주는 게 좋음
  • HashMap의 키
    • 기본 자료형과 참조 자료형 모두 가능
    • But 직접 임의 클래스 만들어 이를 키로 사용할 땐 Object 클래스의 hashCode()와 equals() 잘 구현해야함
    • HashMap에 객체 들어가면 hashCode() 결과값에 따른 버켓(bucket)이라는 목록(list) 형태의 바구니 만들어짐
    • 만약 서로 다른 키가 저장됐는데 hashCode() 결과가 동일하면, 이 버켓에는 여러 개의 값 들어갈 수 있음
    • ➡ get() 호출 시 hashCode() 결과 확인 + 버켓에 들어간 목록에 데이터가 여러 개일 때 equals()로 동일한 값 찾게 됨
    • ➡ 키가 되는 객체 직접 작성 시, 개발툴에서 제공하는 hashCode()와 equals() 자동 생성해주는 기능 사용해 해당 메서드 꼭 구현해야

 

HashMap 객체에 값 넣고 확인하기

Collection Map
add(): 데이터 추가 put(): 데이터 넣기
package d.collection;

import java.util.HashMap;

public class MapSample {
    public static void main(String[] args) {
        MapSample sample = new MapSample();
        sample.checkHashMap();
    }
    public void checkHashMap() {
        HashMap<String, String> map = new HashMap<String, String>();
        map.put("A", "a");
        System.out.println(map.get("A"));
        System.out.println(map.get("B"));
    }
}
//결과
//a
//null
Collection Map
map.get("B")처럼 해당 위치에 값이 없을 때,
Collection은 ArrayIndexOutOfBoundsException 발생
해당 위치가 존재하지 않을 때 개발자에게 알려줘야 하기에 예외 발생
Collection과 달리,
Map에서는 존재하지 않는 키로 get()하면 null 리턴

 

ArrayList vs HashMap

ArrayList HashMap
추가 : add()
수정 : set()
추가 & 수정 : put()
이미 존재하는 키로 값 넣을 때, 기존의 값을 새로운 값으로 대치

 

HashMap 객체의 값 확인하는 다른 방법

  • keySet()
import java.util.Set;

public void checkKeySet() {
    HashMap<String, String> map = new HashMap<String, String>();
    map.put("A", "a");
    map.put("C", "c");
    map.put("D", "d");
    
    Set<String> keySet = map.keySet();
    for(String tempKey : keySet) {
        System.out.println(tempKey + " = " + map.get(tempKey));
    }
}
//결과
//D = d
//A = a
//C = c

 

자바의 자료 구조에서 저장 순서 보장되는 항목은?

저장 순서 중요한 것 저장 순서 중요 x ➡ 데이터 저장순으로 결과 출력 x
List, Queue Set: 데이터 중복 x Map: 키 중복 x

 

  • values()
    • HashMap 객체에 담긴 값만 필요할 때
import java.util.Collection;

public void checkValues() {
    HashMap<String, String> map = new HashMap<String, String>();
    map.put("A", "a");
    map.put("C", "c");
    map.put("D", "d");
    
    Collection<String> values = map.values();
    for(String tempValue : values) {
        System.out.println(tempValue);
    }
}
//결과
//d
//a
//c
  • Map에 저장된 모든 '값' 출력 시 values() 사용하는 게 keySet()으로 모든 키-값 가져오는 것보다 간편

 

  • entrySet()
    • Map에 선언된 Entry라는 타입의 객체 리턴
    • Entry에는 단 하나의 키-값만 저장됨
import java.util.Map.Entry;
import java.util.Set;

public void checkHashMapEntry() {
    HashMap<String, String> map = new HashMap<String, String>();
    map.put("A", "a");
    map.put("B", "b");
    map.put("C", "c");
    map.put("D", "d");
    
    Set<Map.Entry<String, String>> entries = map.entrySet();
    for(Map.Entry<String, String> tempEntry : entries) {
        System.out.println(tempEntry.getKey() + " = " + tempEntry.getValue());
    }
}
//결과
//D = d
//A = a
//B = b
//C = c

 

  • containsKey() & containsValue()
public void checkContains() {
    HashMap<String, String> map = new HashMap<String, String>();
    map.put("A", "a");
    map.put("B", "b");
    map.put("C", "c");
    map.put("D", "d");
    
    System.out.println(map.containsKey("A"));
    System.out.println(map.containsKey("Z"));
    System.out.println(map.containsValue("a"));
    System.out.println(map.containsValue("z"));
}
//결과
//true
//false
//true
//flase

 

  • remove()
public void checkRemove() {
    HashMap<String, String> map = new HashMap<String, String>();
    map.put("A", "a");
    map.remove("A");
    System.out.println(map.size());
}
//결과
//0

TreeMap

HashMap TreeMap
객체의 키 정렬하려면 Arrays 클래스 사용, but 불필요한 객체 생김 HashMap에서의 단점 보완
저장하면서 키 정렬
정렬 순서 : 숫자 > 알파벳 대문자 > 알파벳 소문자 > 한글 (String 같은 문자열 저장 순서)
(객체 및 숫자 저장 시 순서 달라짐)

 

package d.collection;

import java.util.Map;
import java.util.Set;
import java.util.TreeMap;

public class TreeMapSample {
    public static void main(String[] args) {
        TreeMapSample sample = new TreeMapSample();
        sample.checkTreeMap();
    }
    public void checkTreeMap() {
        TreeMap<String, String> map = new TreeMap<String, String>();
        map.put("A", "a");
        map.put("가", "e");
        map.put("1", "f");
        map.put("a", "g");
        
        Set<Map.Entry<String, String>> entries = map.entrySet();
        for(Map.Entry<String, String> tempEntry : entries) {
            System.out.println(tempEntry.getKey() + " = " + tempEntry.getValue());
        }
    }
}
//결과
//1 = f
//A = a
//a = g
//가 = e

 

TreeMap 특징

  • 키를 정렬하여 저장
  • 키의 목록 가져와 출력 시 정렬된 순서대로 제공됨
  • 키가 정렬되기에 데이터가 많을 때 HashMap보다 느림
  • SortedMap 인터페이스 구현했기에 키 정렬 가능
  • 키 정렬 시, 가장 앞에 있는 키(firstKey()), 가장 뒤에 있는 키(lastKey()), 특정 키 뒤에 있는 키(higherKey()), 특정 키 앞에 있는 키(lowerKey()) 등 알 수 있는 메서드 제공

Map 구현한 Properties 클래스

  • Hashtable 확장함 ➡ Map 인터페이스의 모든 메서드 사용 가능
package d.collection;

import java.util.Properties;
import java.util.Set;

public class PropertiesSample {
    public static void main(String[] args) {
        PropertiesSample sample = new PropertiesSample();
        sample.checkProperties();
    }
    public void checkProperties() {
        Properties prop = System.getProperties();
        
        Set<Object> keySet = prop.keySet();
        for(Object tempObject : keySet) {
            System.out.println(tempObject + " = " + prop.get(tempObject));
        }
    }
}
  • System 클래스에 staic으로 선언되어 있는 getProperties() 호출 시, Properties 타입의 객체 리턴

 

System에서 제공하는 Properties 중 자주 사용할 값 목록

속성 설명
user.language 사용자의 사용 언어
user.dir 현재 사용 중인 기본 디렉터리
user.home 사용자 계정의 홈 디렉터리
java.io.tmpdir 자바에서 사용하는 임시 디렉터리
file.encoding 파일의 기본 인코딩
sun.io.unicode.encoding 유니코드 인코딩
path.separator 경로 구분자
file.separator 파일 구분자
line.separator 줄(line) 구분자
  • 위 값들 중 대부분은 IO 클래스의 상수로 정해져있음

 

Properties 클래스가 추가 제공하는 메서드

리턴 타입 메서드 이름 및 매개 변수 설명
void load(InputStream inStream) 파일에서 속성 읽음
void load(Reader reader)
void loadFromXML(InputStream in) XML로 된 속성 읽음
void store(OutputStream out, String comments) 파일에 속성 저장
void store(Writer writer, String comments)
void storeToXML(OutputStream os, String comment) XML로 구성되는 속성 파일 생성
void storeToXML(OutputStream os, String comment, String encoding)
  • 여기서의 comments : 저장되는 속성 파일에 주석으로 저장됨

 

XML

  • eXtensible Markup Language
  • HTML도 XML의 일종
  • 태그로 구성된 텍스트 문서를 의미
  • XML은 서로 데이터 주고 받을 때 표준 정하기 쉬움
  • ex1) 이런 서비스는 어떤 데이터를 정해져 있는 XML 형태로 요청 시, 정해져 있는 형태의 XML로 데이터를 받을 수 있는 기능 제공(요즘은 json 타입 많이 사용)
  • ex2) HTML도 정해져 있는 형태로 파일 만들어 놓으면 IE, 크롬, 사파리 등 브라우저에서 데이터 읽어서(parsing) 화면 구성할 수 있도록 정해놓음

 

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;

public void saveAndLoadProperties() {
    try {
        String fileName = "test.properties";
        
        //파일 다룰 때
        File propertiesFile = new File(fileName);
        
        //파일 저장
        FileOutputStream fos = new FileOutputStream(propertiesFile);
        
        Properties prop = new Properties();
        prop.setProperty("Writer", "Adrian, Black";
        prop.setProperty("WriterHome", "http://www.test.com");
        prop.store(fos, "Basic Properties file");
        fos.close();
        
        //파일 읽기
        FileInputStream fis = new FileInputStream(propertiesFile);
        
        Properties propLoaded = new Properties();
        propLoaded.load(fis);
        System.out.println(propLoaded);
        fis.close();
    } catch(Exception e) {
        e.printStackTrace();
    }
}
//결과
//{WriterHome=http://www.test.com, Writer=Adrian, Black}
  • Hashtable에 toString() 구현되어 있기에 Properties 출력하면 중괄호로 묶임
    test.properties 파일 저장 위치 : 기본적으로 "user.dir"에 지정된 경로에 저장됨
  • test.properties로 살펴보는 .properties 파일의 기본 구성
#Basic Properties file
#Wed XXX XX 09:40:31 KST 201X
WriterHome=http\://www.test.com
Writer=Adrian, Black
  • 키=값으로 구성
  • #: 주석
  • 주석 부분 : store() 사용 시 지정한 주석값
  • 주석 이후 해당 파일 생성 날짜가 자동으로 찍힘

 

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;

public void saveAndLoadPropertiesXML() {
    try {
        String fileName = "test.xml";
        File propertiesFile = new File(fileName);
        FileOutputStream fos = new FileOutputStream(propertiesFile);
        
        Properties prop = new Properties();
        prop.setProperty("Writer", "Adrian, Black";
        prop.setProperty("WriterHome", "http://www.test.com");
        prop.store(fos, "Basic XML Property file");
        fos.close();
        
        FileInputStream fis = new FileInputStream(propertiesFile);
        Properties propLoaded = new Properties();
        propLoaded.load(fis);
        System.out.println(propLoaded);
        fis.close();
    } catch(Exception e) {
        e.printStackTrace();
    }
}
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE properties SYSTEM "http://java.sun.com/dtd/properties.dtd">
<properties>
<comment>Basic XML Property file</comment>
<entry key="WriterHome">http://www.test.com</entry>
<entry key="Writer">Adrian, Black</entry>
</properties>

자바의 자료구조 종합 정리

자바의 자료구조
Collection과 Map 데이터 구조

'Backend > Java' 카테고리의 다른 글

[자바의 신] 26장 (ongoing)  (0) 2022.08.18
[자바의 신] 25장 (ongoing)  (0) 2022.08.18
[자바의 신] 23장  (0) 2022.08.09
[자바의 신] 22장  (0) 2022.08.09
[자바의 신] 21장  (0) 2022.08.09

댓글