▼ Why ? What ?
1일 1알고리즘 스터디에서 "스테이지 별 실패율"을 구해서 "실패율"을 기준으로 "스테이지 번호"를 "내림차순으로 정렬"하는 문제를 풀다가, Collection Framework의 구조, 익명객체와 람다함수의 사용, 그리고 `Comparator` 인터페이스와 `Comparable` 인터페이스의 차이점을 다시 헷갈려하는 것 같아서 따로 공부하며 정리해보았다.
▼ Collection Framework
Hierarchy of Colleciton Framework
Collection 인터페이스, Collections 클래스 ?
- `Collection` 인터페이스를 상속받는 인터페이스 : `List`, `Map`, `Set`, ...
- `Collections` 클래스 : 컬렉션들을 다루기 위해 `Collection` 인터페이스를 구현한 클래스. ( `Arrays` 클래스 느낌 )
[ 참고 자료 - 컬렉션 ] https://ukym-tistory.tistory.com/entry/%EC%BB%AC%EB%A0%89%EC%85%98-%ED%94%84%EB%A0%88%EC%9E%84%EC%9B%8D-Collections-Framework
[Tools] Java 스터디 9주차 : 컬렉션 프레임웍 (Collections Framework)
🌑 컬렉션 프레임웍 (Collections Framework) ✔️ Collections Framework의 핵심 interface 🔸 Vector · Hashtable과 같은 기존의 Collections class들 대신 ArrayList · HashMap 을 사용하자기존의 Collections class들은 호환
ukym-tistory.tistory.com
▼ `Comparator` 인터페이스 vs `Comparable` 인터페이스 (cf. 익명 객체, 람다 표현식)
익명 객체(Anonymous Object)
- 일반적으로 익명 클래스(Anonymous Class)로부터 생성된다.
➙ 익명 클래스는 이름이 없는 클래스이며, 일회성으로 사용된다 ! - `new` 연산자를 사용하여 '인라인'으로 클래스를 정의한다.
- 일반적으로 인터페이스나 추상 클래스를 구현하여 인스턴스를 생성할 때 사용된다 !
람다 표현식(Lamda Expression)
- 함수형 인터페이스(단일 추상 메서드를 가지는 인터페이스)를 구현하는 데 사용된다.
➙ 익명 클래스를 대체할 수 있는 간편한 방법 !
[ 참고 자료 - 더 자세한 내용 ]
[Tools] Java 스터디 12주차 : 람다 (Lamda) & 스트림 (Stream)
🌑 람다식 (Lamda expression) ✔️ 람다식 ? 🔹 람다식(Lamda expression) : 메서드를 하나의 '식(expression)'으로 표현한 것 class, 메서드, 객체 필요 X ➜ 람다식 자체만으로 메서드의 역할을 수행 ➜ 즉, 메
ukym-tistory.tistory.com
Comparator 인터페이스 - `compare()`
- `Comparator`은 특정 비교 방법을 전달하기 위한 함수형 파라미터 성격이 강한 인터페이스이다 !
- `Comparator` 인터페이스는 익명 객체를 생성할 수 있으며, 아래처럼 클래스 외부에서 비교 로직을 정의하는 것이 가능하다 !
익명 객체를 가리키는 참조변수의 이름만 다르게 하면 다양한 구현이 가능하다는 익명 객체의 장점 덕분에, 아래처럼 다양한 비교 기준을 생성하여 활용할 수 있다 !
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
class Student {
private int age;
private int classNumber;
public Student(int age, int classNumber) {
this.age = age;
this.classNumber = classNumber;
}
public int getAge() {
return age;
}
public int getClassNumber() {
return classNumber;
}
@Override
public String toString() {
return "Student{" +
"age=" + age +
", classNumber=" + classNumber +
'}';
}
}
public class Main {
public static void main(String[] args) {
List<Student> students = new ArrayList<>();
students.add(new Student(20, 1));
students.add(new Student(18, 2));
students.add(new Student(22, 1));
students.add(new Student(19, 3));
// Comparator를 사용하여 나이 기준으로 내림차순 정렬 (익명 객체 사용)
Collections.sort(students, new Comparator<Student>() {
@Override
public int compare(Student s1, Student s2) {
return Integer.compare(s2.getAge(), s1.getAge()); // 내림차순 정렬
}
});
// 결과 출력
System.out.println("Sorted by age (descending):");
for (Student student : students) {
System.out.println(student);
}
// Comparator를 사용하여 나이 기준으로 내림차순 정렬 (람다 표현식 사용)
Collections.sort(students, (s1, s2) -> Integer.compare(s2.getAge(), s1.getAge()));
// 결과 출력
System.out.println("\nSorted by age (descending) with lambda:");
for (Student student : students) {
System.out.println(student);
}
}
}
- 아래처럼 익명 객체를 활용해 비교하고자 하는 클래스(`Student`) 외부에서도 비교 로직을 정의할 수 있으며, 따라서 다양한 정렬 기준을 적용할 수 있다 !
// 익명 객체를 사용하여 나이 기준으로 정렬
Collections.sort(students, new Comparator<Student>() {
@Override
public int compare(Student s1, Student s2) {
return s1.getClassNumber() - s2.getClassNumber();
}
});
// 익명 객체를 사용하여 나이 기준으로 오름차순 정렬
Collections.sort(students, new Comparator<Student>() {
@Override
public int compare(Student s1, Student s2) {
return s1.getAge() - s2.getAge();
}
});
// 람다 함수를 사용하여 나이 기준으로 정렬
Collections.sort(students, (s1, s2) -> s1.getClassNumber() - s2.getClassNumber());
// 람다 함수를 사용하여 나이 기준으로 오름차순 정렬
Collections.sort(students, (s1, s2) -> s1.getAge() - s2.getAge());
Comparable 인터페이스 - `compareTo()`
- `Comparable`은 객체 자체에 비교 가능한 특성을 부여해 주기 위한 인터페이스이다 !
- 'Comaparble.compareTo()' 메서드는 자기 자신과 매개변수로 받은 객체를 비교하는 것이기 때문에, `Comparator.compare()`처럼 서로 다른 두 개의 동일한 타입의 객체를 비교하는 것이 아닌 익명 객체(자기자신; this)과 하나의 객체를 비교하는 것이다 !
// Comparble
class Student implements Comparable<Student> {
int age; // 나이
int classNumber; // 학급
Student(int age, int classNumber) {
this.age = age;
this.classNumber = classNumber;
}
@Override
public int compareTo(Student o) {
return this.age - o.age;
}
}
- `Comparable` 인터페이스를 구현한 클래스 내부에 비교 로직(`compareTo`)을 정의해야 하며, 따라서 익명 객체를 활용할 수 없다 !
➙ 아래처럼 람다 함수를 이용해 정렬 방식을 수정하는 것은 가능하다 !
class Student implements Comparable<Student> {
private int age;
private int classNumber;
public Student(int age, int classNumber) {
this.age = age;
this.classNumber = classNumber;
}
public int getAge() {
return age;
}
@Override
public int compareTo(Student other) {
return Integer.compare(this.age, other.age); // 나이 기준으로 오름차순 정렬
}
@Override
public String toString() {
return "Student{" +
"age=" + age +
", classNumber=" + classNumber +
'}';
}
}
public class Main {
public static void main(String[] args) {
List<Student> students = new ArrayList<>();
students.add(new Student(20, 1));
students.add(new Student(18, 2));
students.add(new Student(22, 1));
students.add(new Student(19, 3));
// Comparable 인터페이스의 compareTo 메서드를 사용하여 오름차순 정렬
Collections.sort(students);
// 결과 출력
System.out.println("Sorted by age (ascending):");
for (Student student : students) {
System.out.println(student);
}
// Comparable 인터페이스의 compareTo 메서드를 사용하여 내림차순 정렬
Collections.sort(students, (s1, s2) -> s2.getAge().compareTo(s1.getAge());
// 결과 출력
System.out.println("\nSorted by age (descending) with lambda:");
for (Student student : students) {
System.out.println(student);
}
}
}