Collections

김주영·2022년 11월 5일
0

자바 <면접>

목록 보기
4/9
post-thumbnail

썸넬 Image ref :
https://www.novixys.com/blog/java-collections/

ref가 없는 내용은 자바의 정석 (by 남궁민) 교재 참고함

🌱 컬렉션 클래스란


Vector와 같이 다수의 데이터를 저장할 수 있는 클래스

🌱 핵심 인터페이스


모든 컬렉션 클래스들은 List, Set, Map 중의 하나를 구현하고 있습니다.

순서중복특징예시구현 클래스
ListOO-대기자 명단ArrayList, LinkedList, Stack, Vector 등
SetXX-양의 정수집합, 소수의 집합HashSet, TreeSet
Map-XKey 중복 X, Value 중복 OKey와 Value 쌍 구성우편번호, 지역번호(전화번호)HashMap, TreeMap, HashTable, Properties 등

🌿 Collection 인터페이스 메서드

Java API 문서에는 Object가 아닌 E로 표기되어 있습니다.

Comparator vs Comparable
Wrapper 클래스 타입(ex. Integer, String, Double ...) 이라면 객체에 Comparable이 구현되어 있어 따로 Comparator 을 구현해주지 않아도 됩니다.
사용자 클래스의 경우 사용자가 따로 해당 객체에 Comparable 를 구현해주거나 Comparator 를 구현해주어 파라미터로 넘겨주어야 합니다.

sort(Comparator<\? super E> c)
상속 관계이면서 부모 클래스의 정렬 방식을 따르는 경우도 생각하여 <\? super E>(하한 경계) 로 한 것입니다.

ex)

public class SortArrayList {
    public static void main(String[] args) {

        // ArrayList 준비
        ArrayList<String> list = new ArrayList<>(Arrays.asList("C", "A", "B", "a"));
        System.out.println("원본 : " + list);  // [C, A, B, a]

        // 오름차순으로 정렬
        list.sort(Comparator.naturalOrder());
        System.out.println("오름차순 : " + list);  // [A, B, C, a]

        // 내림차순으로 정렬
        list.sort(Comparator.reverseOrder());
        System.out.println("내림차순 : " + list); // [a, C, B, A]

        // 대소문자 구분없이 오름차순 정렬
        list.sort(String.CASE_INSENSITIVE_ORDER);
        System.out.println("대소문자 구분없이 오름차순 : " + list); // [a, A, B, C]

        // 대소문자 구분없이 내림차순 정렬
list.sort(Collections.reverseOrder(String.CASE_INSENSITIVE_ORDER));
        System.out.println("대소문자 구분없이 내림차순 : " + list); // [C, B, a, A]
    }
}

ref
https://st-lab.tistory.com/167
https://hianna.tistory.com/569

🌱 Arrays


배열을 다루는데 유용한 메소드가 정의되어 있습니다. 정의된 메소드는 모두 static 메소드입니다.

🌿 배열의 복사 - copyOf(), copyOfRange()

  • copyOf()
    배열 전체를 복사

  • copyOfRange()
    배열의 일부를 복사해서 새로운 배열을 만들어 반환
    지정된 범위의 끝은 포함되지 않음

int[] arr = {0,1,2,3,4};
int[] arr1 = Arrays.copyOf(arr, 3) //[0,1,2]
int[] arr2 = Arrays.copyOfRange(arr, 2, 4) //[2,3]

🌿 배열 채우기 - fill(), setAll()

  • fill()
    배열의 모든 요소를 지정된 값으로 채움

  • setAll()
    배열을 채우는데 사용할 함수형 인터페이스를 매개변수로 받음

int[] arr = new int[5];
Arrays.fill(arr, 9); //[9,9,9,9,9]
Arrays.setAll(arr, () -> (int)(Math.random()*5)+1); //[1,5,2,1,1]

🌿 배열의 정렬과 검색 - sort(), binarySearch()

  • sort(배열)
    배열 정렬

  • binarySearch(배열, 찾는 값)
    배열에 저장된 요소를 검색 (저장 위치의 index 반환)
    반드시 배열이 정렬된 상태이어야 올바른 결과를 얻음
    검색 요소가 중복되어 있다면 어떤 index를 받을지 알 수 없음

🌿 배열의 비교와 출력 - equals(), toString()

둘 다 일차원 배열에만 사용 가능

다차원 배열 : deepEquals(), deepToString()

🌿 배열을 List로 변환 - asList(Object... a)

배열을 List에 담아서 반환
매개변수의 타입이 가변인수라서 배열 생성없이 저장할 요소들만 나열하는 것도 가능

List list = Arrays.asList(new Integer[]{1,2,3,4,5});
List list = Arrays.asList(1,2,3,4,5);
list.add(6); //UnsupportedOperationException 예외 발생

asList()가 반환한 리스트의 크기를 변경할 수 없습니다. 즉, 추가 또는 삭제가 불가능합니다. 하지만 저장된 내용은 변경할 수 있습니다.

//크기 변경이 가능한 리스트
List list = new ArrayList(Arrays.asList(1,2,3,4,5));

🌱 Comparable vs Comparator


🌿 인터페이스 정의

  1. Comparable
package java.lang;

public interface Comparable<T> {
	public int compareTo(T o);
}
  1. Comparator
package java.util

@FunctionalInterface
public interface Comparator<T> {
	int compare(T o1, T o2);
    
    boolean equals(Object obj);
}

ref : https://namocom.tistory.com/871

🌿 유사점 및 차이점

둘 다 인터페이스이고 비교에 대한 int 값을 반환한다는 점은 같습니다.

  • 왼쪽 인자 < 오른쪽 인자 : 음수 (No Switching)
  • 왼쪽 인자 = 오른쪽 인자 : 0
  • 왼쪽 인자 > 오른쪽 인자 : 양수 (Switching)

차이점은 속한 패키지와 구현하는 메소드가 다르다는 것입니다.

ref : https://namocom.tistory.com/871

🌿 비교 1 (Type)

public class Person implements Comparable<Person>{
	..
    @Override
    public int compareTo(@NonNull Person p){
    	return this.age - p.getAge(); //나이 기준 비교
    }
}

public class Person implements Comparable<Animal>{
	..
    @Override
    public int compareTo(@NonNull Animal a){
    	return this.age - a.getAge(); //나이 기준 비교
    }
}

//test
o1.compareTo(o2);

public class PersonCompareByAge implements Comparator<Person> {
	@Override
    public int compare(Person p1, Person p2){
    	return p1.getAge() - p2.getAge();
    }
}

//test
Comparator<Person> comp = new PersonCompareByAge();
comp.compare(o1, o2);

Comparable 은 동일 타입이 아닌 클래스의 비교를 지원합니다.
Comparator 의 경우 동일한 타입에 대해서면 비교가 가능합니다.

@NonNull : 메소드 인자에 사용하면 null이 들어올 시 NPE 발생시킴

< ? super T>
상속 관계에 있는 클래스만 자료형으로 받고 싶은 경우(T와 T의 부모 허용)

public static void printData(List <? super Woman> list){
	//자식 Woman, 부모 Person의 데이터만 허용
	for(Object obj : list) //어떤 자료형이든 받아야하므로 Object
		System.out.println(obj);
}

ref : https://butgrin.tistory.com/64

ref : https://namocom.tistory.com/871

🌿 비교 2 (Sort)

Collection(List, Set, Map 등)의 동반 클래스인 Collections에는 리스트의 정렬을 할 수 있게 도와주는 정적 메소드가 두 가지 있습니다.

public java.util;

public class Collections {
	...
    public static <T extends Comparable<? super T>> void sort(List<T> list){
		list.sort(null);
	}

	public static <T> void sort(List<T> list, Comparator<? super T> c){
		list.sort(c);
	}
}

public class Person implements Comparable<Person>{
	...
	@Override
	public int compareTo(Person p){
		return this.id.compareTo(p.id); //id를 오름차순 정렬
	}
}

//test
List<Person> people = new ArrayList<Person>(3);
Collections.sort(people);

//test
List<Person> people = new ArrayList<Person>(3);
Collections.sort(people, Collections.reverseOrder()); //id를 내림차순 정렬

java.util 패키지의 Collections에는 reverseOrder 라는 이름의 정적 메소드가 있어서 역방향 순서의 Comparator 인터페이스를 구현한 구현체를 가지고 있습니다.

위의 것은 정렬에 대한 로직을 클래스 내부에 가지고 있는 것이고 아래는 정렬에 대한 로직을 외부로부터 주입받는 구조라고 볼 수 있습니다.

< ? extends T>
매개변수의 자료형을 특정 클래스를 상속 받은 클래스로 제한함

🔎 정렬 기준을 변경하고 싶은 경우

public class PersonCompareByName implements Comparator<Person>{
	@Override
	public int compare(Person p1, Person p2){
		return p1.getName().compareTo(p2.getName);
	}
}

//test
List<Person> people = new ArrayList<Person>(3);
Collections.sort(people, new PersonCompareByName());

🔎 Comparable로 외부 로직을 주입받을 경우 문제점

Comparable도 멤버로 Comparator를 받게 되면 외부로부터 정렬 로직을 주입받는 식으로 정렬을 할 수 있습니다. 하지만 객체 생성마다 필드에 Comparator가 들어가므로 중복이라는 안티 패턴이 생기게 되고, Comparator의 정렬 기준을 실수로 다른 멤버로 하게 될 경우 원하는 결과가 나지 않게 됩니다.

ref : https://namocom.tistory.com/871

🌿 정렬 메서드 정의


Comparable - compareTo()
Comparator - compare()

return 값이 양수인 경우, 두 값의 자리가 변경되면서 정렬이 이루어진다.

ref : https://lotuus.tistory.com/35

🌿 정리

  • Comparable
    • 클래스 내부에 접근할 수 있으므로 getter와 같이 외부에 데이터를 노출하지 않고도 로직을 만들 수 있는 장점
      (this.id나 p.id 등 직접 프로퍼티에 접근함)

      int compareTo(T o);

    • 객체에 직접 구현을 하기 때문에 참조 데이터 타입이 아닌 기본 데이터 타입에는 적용이 불가능
      (해당 타입에 미리 구현된 비교 메소드가 있다면 호출해서 사용하면 되지만 기본 타입의 경우 메소드 자체가 없어 Comparator를 통해 비교해야 함)
  • Comparator
    • 비교 로직이 객체 자체가 아닌 외부에 위치할 수 있게 해주어 기본 타입도 비교가 가능

      int compare(T o1, T o2);

    • 해당 객체가 외부에 비교를 할 수 있는 값에 대한 접근을 노출해야 함
      (만약 비교 로직을 만들 대상 클래스가 Jar를 통해 라이브러리의 형태로 제공을 받을 경우 클래스(비교 로직)의 직접적인 수정이 불가능)
    • 이런 경우 프로퍼티 접근에 대한 적절한 노출이 되어 있다면 Comparator 인터페이스를 통해 비교 구현이 가능
    • 함수형 인터페이스 -> 자바 8에 추가된 람다 사용 가능

ref : https://namocom.tistory.com/871

Comparable 기본 정렬기준을 구현하는데 사용
Comparator 기본 정렬기준 외에 다른 기준으로 정렬하고자할 때 사용

🌱 Properties


HashTable을 상속받아 구현한 것으로, (String, String)의 형태로 저장하는 보다 단순화된 컬렉션 클래스입니다.

주로 애플리케이션의 환경설정과 관련된 속성을 저장하는데 사용되며 데이터를 파일로부터 읽고 쓰는 편리한 기능을 제공합니다. 또한, 저장순서를 유지하지 않습니다.

🌱 요약


0개의 댓글