Collection과 정렬

Ajisai·2023년 7월 25일
0

Java

목록 보기
13/17

List

contains() 메소드 사용 시 주의사항

결국 포함 여부도 객체 간 비교를 통해 검사하게 된다.
Integer, String같은 건 이미 적절하게 비교가 되도록 equals()가 override되어 있어서 상관 없는데, 임의로 만든 객체의 경우 적절하게 override해야 한다.

ArrayListcontains() 구현을 보면 위와 같다.
내부적으로는 indexOf()의 반환값으로 포함 여부를 판단한다.

다시 indexOf의 구현을 보면 위와 같다.
포함 여부를 검사할 객체가 null이라면 null의 인덱스를 반환하고,
그게 아니라면 equals() 메소드로 비교한다.

결론적으로 equals() 메소드를 적절하게 override해야 의도한 대로 포함 여부를 검사할 수 있다는 것이다.

순회하기

List<String> list = new ArrayList<String>();

...

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

for(String s : list) {                      //방법2
	System.out.println(s); 
}

Iterator<String> iter = list.iterator();    //방법3
while(iter.hasNext()) {
    System.out.println(iter.next());
}

list.stream()                               //방법4
    .forEach(s -> System.out.println(s));

방법2(for-each 문)이나 방법4(Stream 클래스)가 권장된다.
s -> System.out.println(s)와 같은 표현을 람다식 Lambda expression이라 한다.

Queue

  • ArrayDeque implements Deque, Deque extends Queue
  • stack, queue, deque 쓸 일 있으면 ArrayDeque 객체를 생성하자
    LinkedList, Stack보다 ArrayDeque이 더 빠름
  • LinkedListList도 구현하고 Queue도 구현하고 있어서 아무데나 쓸 수 있긴 함
    근데 이제 사실상 List의 구현 객체로만 쓰인다.

정렬

List<MyClass> myClassList = new ArrayList<MyClass>();

...

Collections.sort(list);

정렬이 되려면

  1. 정렬의 기준이 정해져야 한다.
  2. 비교하는 방법이 정해져야 한다.

정수를 정렬하는 방법은 명백하다.
정렬의 기준은 정수의 크기고, 비교하는 방법은 정수의 크기의 대소 비교다.

public class User {
    public String name;
    public int age;
}

그러나 객체는 그렇지 않다.
위와 같은 사용자 클래스를 어떻게 정렬할까?

이를 위해서 Comparable 인터페이스를 구현함으로써 정렬하는 방법을 제시해야 한다.

Comparable

public class User implements Comparable<User> {
    public String name;
    public int age;
    
    @Override
    public int compareTo(User user) {
        if(this.age > user.age) {
            return 1;
        } else if(this.age < user.age) {
            return -1;
        } else {
            return 0;
        }
    }
}
  • 반환 값의 절대값은 중요하지 않고, 부호가 중요하다.
  • 부호에 의해 대소가 결정된다.
  • 서로 같으면 0이다.
  • 리턴 값이 음수면 두 객체의 위치를 바꾸지 않는다.
  • <User>에는 비교 대상의 타입을 쓴다(Generic).

Example

public class User implements Comparable<User> {
    public String name;
    public int age;
    
    public User(String name, int age) {
    	this.name = name;
    	this.age = age;
    }
    
    @Override
    public int compareTo(User user) {
        if(this.age > user.age) {
            return 1;
        } else if(this.age < user.age) {
            return -1;
        } else {
            return 0;
        }
    }

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

import java.util.*;

public class Example {

	public static void main(String[] args) {
		List<User> list = new ArrayList<User>(5);
		list.add(new User("A", 13));
		list.add(new User("B", 93));
		list.add(new User("C", 33));
		list.add(new User("D", 53));
		list.add(new User("E", 73));
		
		System.out.println(list);
		Collections.sort(list);
		System.out.println(list);
	}

}

정렬 방향을 반대로 하고 싶다면 compareTo 메소드에서 1-1만 반대로 써주면 된다.

Comparator

public class Example implements Comparator<TARGET> {
    @override
    public int compare(TARGET target1, TARGET target2) {
        return target1 - target2;
    }
}
  • Comparable과 마찬가지로 양수, 0, 음수 중 하나를 반환하며,
    리턴 값이 음수면 target1target2의 위치를 바꾸지 않는다.
  • 정렬의 대상이 구현하는 게 아니라, 별도의 정렬자 클래스로서 구현된다는 점이 Comparable과 다르다.
  • 위와 같이 클래스로 선언하는 것보다는 익명 객체로 Collection.sort의 parameter로 넘겨주는 경우가 많다(어차피 정렬할 때 말고는 안 쓰니까).
    물론 여러 번 쓰인다면 별도로 선언하는 게 좋을 것이다.

Example

public class User {
    public String name;
    public int age;
    
    public User(String name, int age) {
    	this.name = name;
    	this.age = age;
    }
 
	@Override
	public String toString() {
		return "User [name=" + name + ", age=" + age + "]";
	}
}

import java.util.*;

public class Example {
	public static void main(String[] args) {
		List<User> list = new ArrayList<User>(5);
		list.add(new User("A", 13));
		list.add(new User("B", 93));
		list.add(new User("C", 33));
		list.add(new User("D", 53));
		list.add(new User("E", 73));
		
		System.out.println(list);
		Collections.sort(list, new Comparator<User>() { //Anonymous object
		    public int compare(User user1, User user2) {
		        if(user1.age > user2.age) {
		            return 1;
		        } else if(user1.age < user2.age) {
		            return -1;
		        } else {
		            return 0;
		        }
		    }
		});
		
		System.out.println(list);
	}

}

Lambda expression

Comparator는 메소드가 하나뿐인 함수형 인터페이스 functional interface이므로 람다식도 쓸 수 있다.

import java.util.*;

public class Example {

	public static void main(String[] args) {
		List<User> list = new ArrayList<User>(5);
		list.add(new User("A", 13));
		list.add(new User("B", 93));
		list.add(new User("C", 33));
		list.add(new User("D", 53));
		list.add(new User("E", 73));
		
		System.out.println(list);
		Collections.sort(list, (user1, user2) -> user1.age - user2.age);
		System.out.println(list);
	}

}

Map

  • HashMap, Hashtable(thread-safe HashMap), TreeMap
  • HashMap implements Map
  • Hashtable implements Map
  • TreeMap implements NavigableMap, NavigableMap extends SortedMap
profile
Java를 하고 싶었지만 JavaScript를 하게 된 사람

0개의 댓글

관련 채용 정보