[자바/Java] Collection과 comparator
2024. 2. 4.

Collection Framework는 java.util 패키지로 다수의 데이터를 쉽게 처리하는 방법을 제공한다.

DB처럼 CRUD기능이 중요한데

collection framework 핵심 인터페이스에는 List, Set, Map이 있다.

List

  • 입력 순서가 있는 데이터의 집합
  • 순서가 있기 때문에 데이터의 중복을 허락한다.

주요 메서드

분류  
추가 add(int index, E element)
addAll(int index, Collection<? extends E> c
조회 get(int index)
indexOf(Object o)
lasIndexOf(Obejct o)
listIterator()
삭제 remove(int index)
수정 set(int index, E element)
기타 subList(int fromIndex, int toIndex)

 

List의 대부 생성자를 살펴 보면 Object[] 배열에 저장되는 것을 알 수 있다.

ArrayList

ArrayList도 결국 배열을 사용하기에 태생적으로 배열의 장단점을 그대로 가져간다.

장점 : 간단하다, 사용이 쉽다, 접근 속도가 빠르다

단점 : 크기 변경이 불가능하다, 추가 데이터를 위해 새로운 배열을 만들고 복사 해야함, 비순차적 데이터의 추가, 삭제 하는데에 많은 시간이 걸린다.

 

LinkedList

각 요소를 Node로 정의하고 Node는 다음 요소의 참조 값과 데이터로 구성된다.

각 요소가 다음 요소의 링크 정보를 가지기에 연속적으로 구성될 필요가 없다.

 

활용

  순차적으로 추가/수정/삭제
100만건 추가 시
비 순차 추가/수정/삭제
10만건 추가 시
조회
10만건 조회시
ArrayList 빠름 느림 빠름
LinkedList 느림 빠름 느림

소량의 데이터에서는 크게 차이가 없지만

정적인 데이터나 단순 데이터 조회시에는 ArrayList가 활용도가 더 좋다.

동적인 데이터 추가나 삭제가 많은 작업에서는 LinkedList가 더 좋다.

Set

  • 입력 순서를 관리하지 않음
  • 데이터를 구별할 순서가 없기 때문에 중복이 허용되지 않음
  • Set에는 HahsSet과 SortedSet이 있는데 후자의 경우에는 이진 트리로 정렬된 상태로 요소를 관리한다.

 

데이터 중복 처리

Set에서 데이터를 중복으로 처리하는 기준은 equals() 메서드가 true를 리턴하고 hashCode()의 값이 같은 객체를 의미한다.

예를 들어 String의 name을 가지는 Student라는 클래스가 있다고 가정한다.

Student s1 = new Student("홍길동");
Student s2 = new Student("홍길동");
System.out.println(sp1.equals(sp2)); //false
hset.add(s1);
hset.add(s2);

이와 같은 경우 홍길동이라는 이름을 가진 student가 두개 모두 set에 들어가게된다.

이를 해결하기 위해서는 equals와 hascode를 override해주도록한다,

//SmartPhone.java
@Override
public boolean equals(Object obj) {
	if(obj != null && obj instanceof Student student) {
		return this.name.equals(student.student);
	}
	return false;
}

@Override
public int hashCode() {
	return this.name.hashCode();
}

동일한 이름을 가진 경우 같은 객체로 인식할 수 있도록 이와 같이 작성해주어야한다.

Map

Key와 Value를 하나의 Entry로 묶어서 데이터로 관리한다.

  • Key : Object형태로 데이터의 중복을 허락하지 않는다.
  • Value : Object형태로 데이터 중복을 허락한다.

 

주요 메서드

key와 entry가 set으로 관리된다.

key를 기반으로 사용되기 때문에 따로 수정 메서드가 존재하지 않고 추가 = 수정 이다. 따라서 중복 key가 입력되지 않도록 주의가 필요하다.

분류  
추가 put(K key, V value)
putAll(Map<? extends K, ? extends V> m)
조회 containsKey(Obejct key)
containsValue(Object value)
entrySet()
keySet()
get(Object key)
values()
size()
isEmpty()
삭제 clear()
remove(Object key)
수정 p put(K key, V value)
putAll(Map m)

정렬

정렬이란?

요소를 특정 기준에 대한 내림차순 또느 오름차순으로 배치하는 것

순서를 가지는 collection들만 정렬이 가능하다.

List, SortedSet, SortedMap등

 

Collections.sort()를 이용한 정렬

그렇다면 사용자 정의 객체는 어떻게 정렬을 할 수 있을까?

-> 객체가 Comparable을 구현하고 있는 경우에 sort(List<T> list)를 이용하여 정렬이 가능하다.

Comparable Interface

public interface Comparable<T> {
	public int comparTo(T o);
}

 

ComparTo interface를 implements해서 사용하려면 다음과 같이 compareTo메서드를 ovrride한다.

public class Student implements Comparable<Student>{
	@Override
	public int compareTo(Student o) {
		//이름을 이용해서 정렬
		return number.compareToIgnoreCase(o.name);
	}
}

 

 

Comparator의 활용

class생성하기

객체가 Comparable을 구현하고 있지 않은 경우 혹은 사용자 정의 방법으로 정렬하고 싶은 경우에 comparator를 생성하여 사용한다.

아래는 예를 들어 string을 정렬할 때 글자순이 아니라 길이 순으로 정렬하고 싶을 때 compartor를 작성하는 방법이다.

public class StringLengthComparator implement Comparator<String>{
	@Override
    public int compare(String o1, String o2){
    	int len1 = o1.length();
        int len2 = o2.length();
        return Integer.compare(len1, len2);
    }
}

 

이렇게 정의된 comparator를 사용하려면 sort메소드의 두번째 인자로 사용이 가능하다.

sort(List<T> list, Compartor<? super T> c) 와 같은 메서드가 존재한다.

Collections.sort(names, new StringLengthCompartor());

 

1회성 객체로 anonymous inner class만들기

위와 같은 방법으로 따로 클래스를 정의하지만 여러번 사용되지 않을 거 같다면 1회성 객체로 생성할 수 있다.

Collections.sort(names, new Compator<String>(){
	@Override
    public int compare(String o1, String o2){
    	return Integer.compare(o1.length(), o2.length());
    }
});

 

lambda를 사용해서도 표현할 수 있다.

Collections.sort(names, (o1, o2) ->{
	return Integer.compare(o1.length(), o2.length());
});
myoskin