클라우드 융합 Full-stack 웹 개발자 양성과정/Java

프로그래밍 언어응용-Collection(set), Map(hashMap, properties)

thesunset 2022. 9. 25. 23:13

# Run

 

package com.kh.chap02_set.run;

import java.util.ArrayList;

import java.util.HashSet;

import java.util.Iterator;

import com.kh.chap02_set.model.vo.Student;

public class Run {

 

public static void main(String[] args) {

 

> HashSet

: Value값만 저장, index의 개념이 없음, 순서보장 x, 중복x

[표현법]

HashSet 객체이름 = new HashSet(); //빈 HashSet

 

유형1, 문자열

HashSet<String> hs = new HashSet();

System.out.println(hs);//[]

 

- 값 추가: add(추가할 값)

hs.add("안녕하세요"); //String Pool 
hs.add(new String("반갑습니다.")); //새로 공간 할당=>공간낭비
hs.add("여러분");
hs.add("자바 끝났습니다");
hs.add("월요일은 평가날 입니다");
hs.add("반갑습니다."); //=> 중복이 허용되지 않음 
//hs.add(new Student()); => 자료형이 달라 실행되지 않음

 

//String의 특성 상 안에 담긴 문자열을 기반으로 hashcode를 생성하고, equals를 사용했을 때 String의 경우 주소값이 아닌 문자열을 비교하도록 Object의 메소드가 오버라이딩됨.

 

System.out.println(hs); //저장 순서 보장 x, 중복저장 x** [안녕하세요, 월요일은 평가날 입니다, 자바 끝났습니다, 여러분, 반갑습니다.]

- 크기 구하기 : size()

System.out.println("hs의 크기: " + hs.size()); //5

- 값 삭제: remove(삭제할 값)

hs.remove("월요일은 평가날 입니다");
//인덱스가 없으므로 그대로 값 입력
System.out.println(hs); //=> 삭제됨

- 모든 값 삭제 : clear()

hs.clear();

System.out.println(hs); //=> 모든 값 삭제됨

 

유형2, Student 객체

HashSet<Student> stds = new HashSet();

stds.add(new Student("홍길동", 15, 100));
stds.add(new Student("김**", 40, 99));
stds.add(new Student("송**", 40, 95));
stds.add(new Student("이**", 34, 25));
stds.add(new Student("김**", 40, 99));

System.out.println(stds);
//[Student [name=이**, age=34, score=25], Student [name=김**, age=40, score=99], Student [name=송**, age=40, score=95], Student [name=홍길동, age=15, score=100]]
Student st = new Student("김**", 15, 100);
Student st2 = new Student("김**", 15, 100);

System.out.println(st.hashCode());
//1378192830
System.out.println(st2.hashCode());
//1378192830

중복저장이 가능한 이유는? => 동일객체로 판단이 되지 않기 때문 

 

- HashSet의 특징: 값이 추가될 때 마다 equals()와 hashcode()로 비교 후 둘 다 결과가 true일 경우 동일객체로 판단

 

//equals() : 현재 객체의 주소값을 비교해서 결과반환(같으면 true) : boolean

//hashCode() : 현재 객체의 주소값을 해싱 알고리즘을 돌려서 10진수로 반환 : int 

 

System.out.println(st.equals(st2)); //true

 

 

* 총정리

: HashSet에 객체를 담을 때 내부적으로 equals 메소드랑 hashCode메소드를 기준으로 값이 일치하는지를 비교하고 담는다.

==equals의 결과가 true이고 (그리고) hashCode의 값도 일치한다면

=> 동일객체로 판단(중복저장을 안 함)

 

* Object클래스

* equals() : 두 객체의 주소값을 비교해서 일치하면true

* hashCode() : 객체의 주소값을 해싱해서 10진수 형태로 반환

=> 반환한 결과들끼리 비교 => 두 결과가 모두 일치해야만 한다.

 => 내용물은 같은데 주소값이 달라서 동일객체가 아닌 것으로 판단이 되면서 중복저장 => 방지하고 싶다면?

= equals메소드와 hashCode메서드를 오버라이딩해서 사용해야 한다.

 

* Student 클래스

 

* hashCode() : 세 필드값을 하나의 문자열로 만들고 해시코드값을 만들어서 반환

* equals() : 세 필드의 값이 모두 일치하면 true

 

- HashSet에 들어있는 모든 값들을 출력하는 방법

 

1. 반복문 => 인덱스 개념 but hashCode는 인덱스 개념이 없음

for(Student s : stds) {
	System.out.println(s);
} //=> 향상된 for문 사용

2.HashSet의 내용물을 ArrayList에 담아서 

//인덱스를 이용해서 출력

 

1단계) ArrayList객체 생성

ArrayList list = new ArrayList();

2단계) addAll(collection c) 사용 - 전부 추가 

list.addAll(stds); 

for(int i = 0; i<list.size(); i++) {
	System.out.println(list.get(i));
}

1+2단계) 생성과 동시에 초기화

ArrayList<Student> student = new ArrayList(stds);

for(int i = 0; i<list.size(); i++) {
System.out.println(list.get(i));
}

 

3. Interator(반복자) => HashSet클래스에서 제공

- String의 StringTokenizer과 비슷한 원리

- Set계열과 List계열에서 호출이 가능=> Map계열에서는 바로 호출이 불가능 

 

Iterator it = stds.iterator();

/*

System.out.println(it.next());
System.out.println(it.next());
System.out.println(it.next());
System.out.println(it.next()); 
System.out.println(it.next());//NosuchElementException (RunTimeException의 자손)

*/

- hasNext()사용하기*************: //it에 next로 더 빼올 값이 있는지 있으면 true, 없으면 false

while(it.hasNext()) {
	System.out.println(it.next());
}

 

# Student

 

package com.kh.chap02_set.model.vo;
public class Student {

private String name;
private int age;
private int score;

public Student() {
}
public Student(String name, int age, int score) {
this.name = name;
this.age = age;
this.score = score;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public int getScore() {
return score;
}
public void setScore(int score) {
this.score = score;
}

@Override
public String toString() {
return "Student [name=" + name + ", age=" + age + ", score=" + score + "]";
}

직접 hashCode()와 equals()를 오버라이딩 해보면, 

 

//hashCode()

@Override
public int hashCode() {
// 객체들의 주소 16진수 어쩌고저쩌고 뭐시뭐시기를해가지고 10진수로 반환
return (name + age + score).hashCode();
// (이름 + 나이 + 점수)
// "김**15100"
// "김**5050"
// (이름 + 나이 + 점수).해싱
}



// equals()

public boolean equals(Object obj) {
Student other = (Student)obj;

// 이름, 나이, 점수
// 셋중에 하나라도 다르면 false값 리턴
if(!this.name.equals(other.name) || this.age != other.age || this.score != other.score) {
return false;
}
// 필드값이 모두다 동일하다면 true값 리턴
return true;
// 결과반환 true / false
}

//hashCode

@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + age;
result = prime * result + ((name == null) ? 0 : name.hashCode());
result = prime * result + score;
return result;
}

 

//equals()

 

@Override

public boolean equals(Object obj) {
//현재 객체(this)와 obj를 비교

if (this == obj) //현재 객체와 비교객체의 주소값이 일치하는가?
return true; // == 같은 곳을 가리키고 있음 == 모든 필드값이 일치 

if (obj == null) //비교대상이 null
return false; //비교할 가치가 x

if (getClass() != obj.getClass())//메소드 타입비교
return false;

//위에 세가지 조건을 만족하지 않았을 경우
//각 내용물을 다 비교

Student other = (Student) obj;
if (age != other.age) //현재 객체랑 들어온 객체랑 나이가 다른 경우 
return false;
if (name == null) { //현재 객체 이름값이 null일 경우
if (other.name != null) //비교 객체 이름 값이 null이 아닐 경우 
return false;
} else if (!name.equals(other.name)) //현재 객체이름과 비교객체 이름이 다를 경우
return false;
if (score != other.score) //점수가 달라도
return false;
//모든 경우를 빗겨나갔을 경우에는 true
return true;
}
}

# Map

 

  • Vo
package com.kh.chap03_map.chap03_map.part01_hashMap.model.vo;

public class Burger {

	private String flavor; //맛
	private int calorie;//열량
	
	public Burger() {
	}

	public Burger(String flavor, int calorie) {
		this.flavor = flavor;
		this.calorie = calorie;
	}
	public String getFlavor() {
		return flavor;
	}
	public void setFlavor(String flavor) {
		this.flavor = flavor;
	}
	public int getCalorie() {
		return calorie;
	}
	public void setCalorie(int calorie) {
		this.calorie = calorie;
	}
	@Override
	public String toString() {
		return "Burger [flavor=" + flavor + ", calorie=" + calorie + "]";
	}
}
  • Run

package com.kh.chap03_map.chap03_map.part01_hashMap.run;

 

import java.util.HashMap;

import java.util.Iterator;

import java.util.Map.Entry;

import java.util.Set;

 

import com.kh.chap03_map.chap03_map.part01_hashMap.model.vo.Burger;

 

public class Run {

 

public static void main(String[] args) {

 

> hashMap

[표현법]

HashMap 이름 = new HashMap();

 

key + value 세트로 추가 

//key == 식별자 =>버거 이름 

//value == 값 =>맛, 열량 

HashMap<String, Burger> hm = new HashMap();

//key, 클래스자료형

 

//비어있는 해시 맵에 추가해보자

 

- ArrayList, HashSet => add()

-> List계열 Set계열 Collection을 구현한 클래스

 

//HashMap => put() - Map계열

// => key + value 세트로 추가 

 

1. put(K key, V value) : 맵공간에  key + value 세트 추가 

 

hm.put("싸이버거", new Burger("바삭바삭한 맛", 400));
hm.put("와퍼",  new Burger("근본있는맛", 550));
hm.put("상하이 스파이시 버거", new Burger("매콤한맛", 360));
hm.put("블랙오징어버거", new Burger("매운맛", 350));
hm.put("징거버거", new Burger("징거버거맛", 350));
hm.put("88서울비프버거", new Burger("부드럽고 고소한 에그 양배추 샐러드에\n"+
						"쫄깃 바삭 크로켓 번, 육즙 가득 쇠고기 패티로 풍미 가득한\n" + 
						"88년 추억의 맛을 담은 버거!", 521));
                        
 System.out.println(hm);// {상하이 스파이시 버거=Burger [flavor=매콤한맛, calorie=360], 88서울비프버거=Burger [flavor=부드럽고 고소한 에그 양배추 샐러드에 쫄깃 바삭 크로켓 번, 육즙 가득 쇠고기 패티로 풍미 가득한 88년 추억의 맛을 담은 버거!, calorie=521], 와퍼=Burger [flavor=근본있는맛, calorie=550], 블랙오징어버거=Burger [flavor=매운맛, calorie=350], 징거버거=Burger [flavor=징거버거맛, calorie=350], 싸이버거=Burger [flavor=바삭바삭한 맛, calorie=400]}

 

//값의 저장 순서 유지 x , Key=Value

//Value값의 중복 저장 허용 => Key값은 중복 안 됨.

hm.put("88서울비프버거", new Burger("옛날맛",521)); //기존의 Key값에 Value값이 덮어씌워진다.

System.out.println(hm); //{상하이 스파이시 버거=Burger [flavor=매콤한맛, calorie=360], 88서울비프버거=Burger [flavor=옛날맛, calorie=521], 와퍼=Burger [flavor=근본있는맛, calorie=550], 블랙오징어버거=Burger [flavor=매운맛, calorie=350], 징거버거=Burger [flavor=징거버거맛, calorie=350], 싸이버거=Burger [flavor=바삭바삭한 맛, calorie=400]}

Key는 식별자 개념! => Key로 Value를 찾아감

 

2. get(Object key): Object

=> 제네릭 설정을 해놨기 때문에 매개변수는 String, 반환형은 Burger

해당 key값에 해당하는 value값을 반환해주는 메소드

 

System.out.println(hm.get("88서울비프버거")); 
//Burger [flavor=옛날맛, calorie=521]

 

Burger ob = /*(Burger)*/hm.get("와퍼");

제네릭 설정을 안 해놨다면 매 번 다운캐스팅을 했어야 함

 

3. size() : 맵에 담겨있는 요소의 개수

System.out.println(hm.size()); //6

 

4. replace(K key, V value) : 해당 Key값을 찾아서 Value를 변경시켜줌

hm.replace( "블랙오징어버거", new Burger("검은 오징어맛", 361));

//기존에 존재하지 않는 키값을 제시했을 땐 추가가 안됨
hm.replace("없는 버거", new Burger("없는 맛",0));

System.out.println(hm);
//{상하이 스파이시 버거=Burger [flavor=매콤한맛, calorie=360], 88서울비프버거=Burger [flavor=옛날맛, calorie=521], 와퍼=Burger [flavor=근본있는맛, calorie=550], 블랙오징어버거=Burger [flavor=검은 오징어맛, calorie=361], 징거버거=Burger [flavor=징거버거맛, calorie=350], 싸이버거=Burger [flavor=바삭바삭한 맛, calorie=400]}

5. remove(Object key) => 해당 키값을 찾아서 => Key + Value 세트를 지워주는 메소드

 

hm.remove("블랙오징어버거");

System.out.println(hm);
//{상하이 스파이시 버거=Burger [flavor=매콤한맛, calorie=360], 88서울비프버거=Burger [flavor=옛날맛, calorie=521], 와퍼=Burger [flavor=근본있는맛, calorie=550], 징거버거=Burger [flavor=징거버거맛, calorie=350], 싸이버거=Burger [flavor=바삭바삭한 맛, calorie=400]}

 

해시맵에 들어있는 모든 요소들에 순차적으로 접근하고자 할 때 ?

- for문 X, 향상된 for문

 

어느 방법을 써야할까?

//List에 addAll 하는 방법 => collection라인이 아니라서 불가능

//Interator를 쓰는 방법 => 바로 호출은 안됨

 

====> Map계열을 Set계열로 바꿔서 => Iterator을 사용할 것

 

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

=>HashMap에서 제공하는 메소드, Set에 key들만 담아준다. 반환형은 Set

 

1단계: Key들만 Set에 담는다.

Set<String> keyset = hm.keySet();

 

2단계: 1단계에서 만들어진 Set내용물을 Iterator에 담기

Iterator<String> itKey = keyset.iterator();

 

3단계 : Iterator로 부터 반복문 이용해서 순차적으로 key - value 뽑기

while(itKey.hasNext()) {

String key = itKey.next();

System.out.println(key + "-" + hm.get(key));

} 

 

2. entrySet() 이용하는 방법

 

1)Map에 있는 key + value 세트를 

Entry형식으로 Set에 담기 

 

Set<Entry<String, Burger>> entrySet = hm.entrySet();

	for(Entry<String, Burger> e :entrySet){
	System.out.println(e.getKey() + "-" + e.getValue());
}

* Map계열 특성상 요소들에 순차적으로 접근할 직접적인 방법이 없음 

 => Map계열을 Set계열로 바꿔서 => 반복문, ArrayList로 바꿔서 반복문 

 

* Iterator를 쓰는 방법

* => Map계열을 Set계열로 바꾸는 2가지 방법: keySet(), entrySet()

 

# Properties

 

package com.kh.chap03_map.chap03_map.part01_hashMap.run;

 

import java.io.FileInputStream;

import java.io.FileNotFoundException;

import java.io.FileOutputStream;

import java.io.IOException;

import java.util.Properties;

 

public class PropertiesRun1 {

 

public static void main(String[] args) {

- Properties : Map계열 -> key + value세트로 저장됨

// Key와 Value 모두 String형을 다룬다.

 

[표현법]

Properties 이름 = new Properties();

 

Properties prop = new Properties();

prop.put("와퍼", new Burger("근본있는맛", 1550));

System.out.println(prop);
//{와퍼=Burger [flavor=근본있는맛, calorie=1550]}
System.out.println(prop.get("와퍼"));
//Burger [flavor=근본있는맛, calorie=1550]

 

Properties의 용도 => 파일 입출력을 하기 위함

* key + value세트로 파일로 기록한다던가

* 파일로부터 읽어오는 용도로 많이 사용됨

=> .properties 파일 확장자 

 

* 자주 변경되지 않는 설정파일이나

* 해당 프로그램이 기본적으로 가져야 할 정보들을 담는 파일

 

- String, String형으로 담아보자

 

prop.setProperty("List", "ArrayList" );
prop.setProperty("Set", "HashSet" );
prop.setProperty("Map", "HashMap" );
prop.setProperty("Map", "Properties" ); //덮어쓰기

System.out.println(prop);
//{Map=Properties, List=ArrayList, Set=HashSet}

Properties inputProp = new Properties(); //******잘 기억하기 

try {
prop.store(new FileOutputStream("test.properties"), "Properties Test");

- store(OutputStream os, String Comments): 파일을 기록할 때 쓰는 메소드

//key = value형태로 파일이 출력됨.

 

//입력

System.out.println("\n여기서부터는 입력");

inputProp.load(new FileInputStream("test.properties"));

//load(InputStream is) : 파일로부터 읽어올 때 쓰이는 메소드

 

System.out.println(inputProp.get("List")); //ArrayList
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}

# Properties 2

package com.kh.chap03_map.chap03_map.part01_hashMap.run;

 

import java.io.FileNotFoundException;

import java.io.FileOutputStream;

import java.io.IOException;

import java.util.Properties;

 

public class PropertiesRun2 {

 

public static void main(String[] args) {

 

//.xml

//다양한 프로그래밍 언어 간에 호환성이 좋다. 

 

Properties prop = new Properties();

 

prop.setProperty("List", "ArrayList" );

prop.setProperty("Set", "HashSet" );

 

System.out.println(prop);

 

try {

prop.storeToXML(new FileOutputStream("test.xml"),  "안녕하세요.");

//storeTOXML(OutputStream os, String comments)

//Properties 객체의 키 + 밸류 세트를 XML파일로 저장

 

//불러오기: loadFromXML(InputStream is)

 

} catch (FileNotFoundException e) {

e.printStackTrace();

} catch (IOException e) {

e.printStackTrace();

}

 

 

}

}