Java Collection 프레임워크 Ⅱ

young-gue Park·2023년 2월 9일
0

Java

목록 보기
2/11
post-thumbnail

⚡ Java Collection 프레임워크 Ⅱ


📌 Set 인터페이스

🔷 순서와 상관없이 중복을 허용하지 않는 경우에 사용한다.

  • ex) 회원 아이디, 주민등록번호 등
  • Set 인터페이스를 구현한 대표 클래스로 HashSet과 TreeSet이 있다.

🔷 HashSet 클래스

  • 집합 자료 구조를 구현하며 중복을 허용하지 않는다.
  • HashSet에 중복된 값은 추가되지 않는다.
  • 자료가 추가된 순서와 상관없이 출력된다.

🖥 테스트 코드

package hashset;

import java.util.HashSet;

public class HashSetTest {

	public static void main(String[] args) {
		HashSet<String> hashSet = new HashSet<>();
		
		hashSet.add(new String("박영규"));
		hashSet.add(new String("백준아"));
		hashSet.add(new String("이도영"));
		hashSet.add(new String("김청"));
		hashSet.add(new String("박영규"));
		
		System.out.println(hashSet);
	}
}

🖨 출력

🔷 HashSet을 이용한 회원 관리 프로그램 구현

🖥 MemberHashSet.java

package hashset;

import java.util.*;
import collection.Member;

public class MemberHashSet {
	private HashSet<Member> hashSet;
	
	public MemberHashSet() {
		hashSet = new HashSet<Member>();
	}
    
	// 회원 추가 
	public void addMember(Member member) {
		hashSet.add(member);
	}
	
    // 회원 삭제
    // Iterator를 활용한 순회를 이용
	public boolean removeMember(int memberId) {
		Iterator<Member> ir = hashSet.iterator();
		
		while(ir.hasNext()) {
			Member member = ir.next();
			int tempId = member.getMemberId();
			if(tempId == memberId) {
				hashSet.remove(member);
				return true;
			}
		}
		System.out.println(memberId + "가 존재하지 않습니다.");
		return false;
	}
	
    // 모든 회원 출력
	public void showAllMember() {
		for(Member member : hashSet) {
			System.out.println(member);
		}
		System.out.println();
	}
}

🖥 MemberHashSetTest.java

package hashset;

import collection.Member;

public class MemberHashSetTest {

	public static void main(String[] args) {
		MemberHashSet memberHashSet = new MemberHashSet();
		
		Member memberLee = new Member(1, "이도영");
		Member memberPark = new Member(2, "박영규");
		Member memberKim = new Member(3, "김청");
		Member memberBaek = new Member(4, "백준아");
		
		memberHashSet.addMember(memberLee);
		memberHashSet.addMember(memberPark);
		memberHashSet.addMember(memberKim);
		memberHashSet.addMember(memberBaek);
		memberHashSet.showAllMember();
		
		Member memberSpy = new Member(3, "김솔");
		memberHashSet.addMember(memberSpy);
		memberHashSet.showAllMember();
	
	}
}

🖨 출력

어라 뭔가 이상하다..?

  • 같은 아이디의 회원을 추가하면 아이디는 같지만 이름은 다른 두명의 회원이 되어버린다.
  • Member 클래스에 같은 객체를 처리하는 방법을 따로 구현해야한다.

🖥 Member.java

package collection;

public class Member {
	private int memberId;
	private String memberName;
	
	public Member(int memberId, String memberName) {
		this.memberId = memberId;
		this.memberName = memberName;
	}
	
	public int getMemberId() {
		return memberId;
	}
	
	public void setMemberId(int memberId) {
		this.memberId = memberId;
	}
	
	public String getMemberName() {
		return memberName;
	}
	
	public void setMemberName(String memberName) {
		this.memberName = memberName;
	}
	
	@Override
	public String toString() {
		return memberName + " 회원님의 아이디는 " + memberId + "입니다.";
	}
	
	// hashCode()메서드가 회원 아이디를 반환 하도록 재정의
	@Override
	public int hashCode() {
		return memberId;
	}
	
	// 매개변수로 받은 회원 아이디가 자신의 회원 아이디와 같다면 true 반환
	@Override
	public boolean equals(Object obj) {
		if(obj instanceof Member) {
			Member member = (Member)obj;
			if(this.memberId==member.memberId) {
				return true;
			}
			else {
				return false;
			}
		}
		return false;
	}
}

🖨 이전 프로그램 재출력 결과

스파이는 equals()가 보내버렸으니 안심하라구 :)


🔷 HashSet 클래스

  • 자료의 중복을 허용하지 않으면서 출력 결과 값을 정렬하는 클래스

💡 자바의 collection 인터페이스나 Map 인터페이스를 구현한 클래스 중 Tree로 시작하는 클래스는 데이터를 추가한 후 결과를 출력하면 결과 값이 정렬된다.

  • 트리는 자료 사이에 계층구조를 나타내는 자료구조다.

기억하지 못하는 그대를 위하여
자바스크립트로 알아보는 자료구조 (트리)

🖥 TreeSet 테스트 코드

package treeset;

import java.util.*;

public class TreeSetTest {

	public static void main(String[] args) {
		TreeSet<String>treeSet = new TreeSet<String>();
		
		treeSet.add("박영규");
		treeSet.add("백준아");
		treeSet.add("이도영");
		treeSet.add("김청");
		
		for(String str : treeSet) {
			System.out.println(str);
		}
	}
}

🖨 출력

한글 순으로 정렬되어 출력되는 것을 볼 수 있다.

🔷 TreeSet을 이용한 회원 관리 프로그램 구현

  • 동일한 set 인터페이스 이기 때문에 HashSet 대신에 TreeSet만 선언하여 생성하면 나머지 코드는 같다.

🖥 MemberTreeSet.java

package treeset;

import java.util.*;
import collection.Member;

public class MemberTreeSet {
	private TreeSet<Member> treeSet;
	
	public MemberTreeSet() {
		treeSet = new TreeSet<Member>();
	}
	
	public void addMember(Member member) {
		treeSet.add(member);
	}
	
	public boolean removeMember(int memberId) {
		Iterator <Member>ir = treeSet.iterator();
		
		while(ir.hasNext()) {
			Member member = ir.next();
			int tempId = member.getMemberId();
			if(tempId == memberId) {
				return true;
			}
			else {
				return false;
			}
		}
		return false;
	}
	
	public void showAllMember() {
		for(Member member : treeSet) {
			System.out.println(member);
		}
		System.out.println();
	}
}

🖥 MemberTreeSetTest.java

package treeset;

import collection.Member;

public class MemberTreeSetTest {

	public static void main(String[] args) {
		MemberTreeSet memberTreeSet = new MemberTreeSet();
		
		Member memberLee = new Member(1, "이도영");
		Member memberPark = new Member(2, "박영규");
		Member memberKim = new Member(3, "김청");
		Member memberBaek = new Member(4, "백준아");

		memberTreeSet.addMember(memberLee);
		memberTreeSet.addMember(memberPark);
		memberTreeSet.addMember(memberKim);
		memberTreeSet.addMember(memberBaek);
		memberTreeSet.showAllMember();
		
		Member memberSpy = new Member(2, "김청");
		memberTreeSet.addMember(memberSpy);
		memberTreeSet.showAllMember();
	}
}

⚠ 다만 그대로 구현했을 때 난데없이 이런 오류가 발생한다.

  • Member 클래스가 Comparable 인터페이스를 구현하지 않았다고 한다.
  • 이것은 Member 클래스를 TreeSet의 요소로 추가할 때 어떤 기준으로 노드를 비교하여 트리를 형성해야 하는지를 구현하지 않았다는 뜻이다.
  • 이 때 Comparable 인터페이스나 Comparator 인터페이스를 Member 클래스에 구현하면 된다.

💡 Comparable 인터페이스
자기 자신과 전달받은 매개변수를 비교하는 인터페이스로 compareTo() 추상메서드를 포함하고 있다.

🖥 Comparable을 추가 구현한 Member.java

package collection;

public class Member implements Comparable <Member> {
	private int memberId;
	private String memberName;
	
	public Member (int memberId, String memberName) {
		this.memberId = memberId;
		this.memberName = memberName;
	}
	
	public int getMemberId() {
		return memberId;
	}
	
	public void setMemberId(int memberId) {
		this.memberId = memberId;
	}
	
	public String getMemberName() {
		return memberName;
	}
	
	public void setMemberName(String memberName) {
		this.memberName = memberName;
	}
	
	@Override
	public String toString() {
		return memberName + " 회원님의 아이디는 " + memberId + "입니다.";
	}
	
	// hashCode()메서드가 회원 아이디를 반환 하도록 재정의
	@Override
	public int hashCode() {
		return memberId;
	}
	
	// 매개변수로 받은 회원 아이디가 자신의 회원 아이디와 같다면 true 반환
	@Override
	public boolean equals(Object obj) {
		if(obj instanceof Member) {
			Member member = (Member)obj;
			if(this.memberId==member.memberId) {
				return true;
			}
			else {
				return false;
			}
		}
		return false;
	}
	
	// 메서드 재정의를 통해 추가한 회원 이름과 매개변수로 받은 회원 이름을 비교함
	// -1을 곱하느냐 아니냐에 따라 오름차순과 내림차순 정렬이 결정되고, 아이디도 얼마든지 가능하다.
	@Override
	public int compareTo(Member member) {
		return ((this.memberName.charAt(0) - member.memberName.charAt(0)) *(-1));
	}
}

🖨 출력

다른 아이디지만 이름이 같은 김청이 들어오지 못한 모습이다.

🔷 Comparator 인터페이스

  • Comparable 처럼 정렬을 구현하는데 사용하는 인터페이스
  • Compare() 메서드를 구현 해야한다.
  • 일반적으로 Comparable을 더 많이 사용한다.

🤔 그럼 이 친구는 언제 쓰는건가요?

  • 만약 어떤 클래스가 이미 Comparable 인터페이스를 구현했을 때 사용할 수 있다. 예를 들어 String 클래스는 이미 Comparable 인터페이스를 구현하고 있는데다가 final로 선언되어 있어서 compareTo() 메서드를 재정의할 수 없다. 이러한 경우에 Comparator를 사용한다.

🖥 ComparatorTest.java

package treeset;

import java.util.*;

class MyCompare implements Comparator<String> {
	@Override
	public int compare(String s1, String s2) {
		return (s1.compareTo(s2)) /** -1*/;
	}
}

public class ComparatorTest {

	public static void main(String[] args) {
    	// 생성자에 Comparator를 구현한 객체를 매개변수로 전달한다.
		Set<String> set = new TreeSet<String>(new MyCompare());
		set.add("꽃가루를 날려");
		set.add("폭죽을 더 크게 터뜨려");
		set.add("샴페인을 더 크게 터뜨려");
		
		System.out.println(set);
	}
}

🖨 출력


📌 Map 인터페이스

🔷 자료를 쌍(pair)으로 관리하는 데 필요한 메서드가 정의되어 있는 인터페이스

  • key-value 쌍으로 이루어진 객체의 key 값은 유일하며 value 값은 중복될 수 있다.
  • Map 인터페이스를 구현한 클래스는 내부적으로 해시 알고리즘에 의해 구현되어 있다.
  • ex) HashMap 클래스, TreeMap 클래스

🔷 HashMap 클래스

  • 해시 방식으로 자료를 관리하는 클래스

해시브라운만 떠올리는 당신을 위해
자바스크립트로 보는 자료구조 (해시테이블)

  • 해시 함수 표현 방식은 다음과 같다.
index = hash(key)
  • 적정 수준이 되면 테이블을 확장해 해시 충돌 발생 확률을 낮춘다.
  • key 값이 중복될 수 없으므로 equals() 메서드와 hashcode() 메서드를 재정의하여 사용하는 것이 좋다.

🔷 HashMap으로 구현한 회원 관리 프로그램

🖥 MemberHashMap.java

package collection.map;

import java.util.*;

import collection.Member;

public class MemberHashMap {
	private HashMap<Integer, Member> hashMap;
	
	public MemberHashMap() {
		hashMap = new HashMap<Integer, Member>();
	}
	
    // 회원을 key-value 쌍으로 추가
	public void addMember(Member member) {
		hashMap.put(member.getMemberId(), member);
	}
	
    // 입력된 키 값이 존재하는 회원을 삭제
	public boolean removeMember(int memberId) {
		if(hashMap.containsKey(memberId)) {
			hashMap.remove(memberId);
			return true;
		}
		System.out.println(memberId + "가 존재하지 않습니다.");
		return false;
	}
	
    // 전체 회원 출력
	public void showAllMember() {
		Iterator<Integer> ir = hashMap.keySet().iterator();
		while(ir.hasNext()) {
			int key = ir.next();
			Member member = hashMap.get(key);
			System.out.println(member);
		}
		System.out.println();
	}
}

❗ 회원 아이디로 쓰인 Integer형은 이미 equals()와 hashcode()가 재정의 되어 있기 때문에 다시 재정의할 필요가 없다.

🖥 MemberHashMapTest.java

package collection.map;

import collection.Member;

public class MemberHashMapTest {

	public static void main(String[] args) {
		MemberHashMap memberHashMap = new MemberHashMap();
		
		Member memberLee = new Member(1, "이도영");
		Member memberPark = new Member(2, "박영규");
		Member memberKim = new Member(3, "김청");
		Member memberBaek = new Member(4, "백준아");
		
		memberHashMap.addMember(memberLee);
		memberHashMap.addMember(memberPark);
		memberHashMap.addMember(memberKim);
		memberHashMap.addMember(memberBaek);
		
		memberHashMap.removeMember(1);
		memberHashMap.showAllMember();
	}
}

🖨 출력

회원 삭제까지 야무지게 돌아간다.

💡 HashTable 클래스 역시 존재한다. 이 클래스는 Vector 클래스와 마찬가지로 멀티스레드를 위한 동기화를 제공한다. 이 말은 멀티스레드 환경이 아니라면 HashMap을 사용하는 것을 권장한다는 뜻이다.


🔷 TreeMap 클래스

🔷 key 값으로 자료를 정렬할 수 있는 클래스

  • TreeSet과 마찬가지로 이진검색트리로 구현되어있다.
  • key 값에 해당하는 클래스에 Comparable이나 Comparator 인터페이스를 구현해야한다.

❗ 예제에서 key 값으로 쓰일 Integer형은 이미 Comparable 인터페이스가 구현되어 있어서 따로 구현할 필요가 없다.

🖥 MemberTreeMap.java

package collection.map.treemap;

import java.util.*;
import collection.Member;

public class MemberTreeMap {
	private TreeMap<Integer, Member> treeMap;
	
	public MemberTreeMap() {
		treeMap = new TreeMap<Integer, Member>();
	}
	
    // 회원 추가
	public void addMember(Member member) {
		treeMap.put(member.getMemberId(), member);
	}
	
    // 회원 삭제
	public boolean removeMember(int memberId) {
		if(treeMap.containsKey(memberId)) {
			treeMap.remove(memberId);
			return true;
		}
		System.out.println(memberId + "가 존재하지 않습니다.");
		return false;
	}
	
    // 전체 회원 보기
	public void showAllMember() {
		Iterator<Integer> ir = treeMap.keySet().iterator();
		while(ir.hasNext()) {
			int key = ir.next();
			Member member = treeMap.get(key);
			System.out.println(member);
		}
		System.out.println();
	}
}

🖥 MemberTreeMapTest.java

package collection.map.treemap;

import collection.Member;

public class MemberTreeMapTest {

	public static void main(String[] args) {
		MemberTreeMap memberTreeMap = new MemberTreeMap();
		
		Member memberLee = new Member(1, "이도영");
		Member memberPark = new Member(2, "박영규");
		Member memberKim = new Member(3, "김청");
		Member memberBaek = new Member(4, "백준아");
		
		memberTreeMap.addMember(memberLee);
		memberTreeMap.addMember(memberPark);
		memberTreeMap.addMember(memberKim);
		memberTreeMap.addMember(memberBaek);
		
		memberTreeMap.showAllMember();
		
		memberTreeMap.removeMember(2);
		memberTreeMap.showAllMember();

	}

}

🖨 출력


컬렉션 프레임워크에서 제공하는 여러 클래스를 살펴보았다.
유용하게 사용할 수 있길 기대한다.

profile
Hodie mihi, Cras tibi

0개의 댓글