import java.util.Arrays;
public class Solution {
public static void main(String[] args) {
int[][] meetings = {
{1, 4}, // 1번팀
{3, 5}, // 2번팀
{0, 6}, // 3번팀
{5, 7}, // 4번팀
{3, 8}, // 5번팀
{5, 9}, // 6번팀
{6, 10}, // 7번팀
{8,11}};
int maxCount = maxMeetings(meetings);
System.out.println(maxCount);
}
private static int maxMeetings(int[][] meetings) {
//******여기서 람다식이 사용됨*******
Arrays.sort(meetings,(a,b)->a[1]-b[1]);
int count = 1;
int lastEndTime = meetings[0][1];
for(int i=1; i<meetings.length; i++){
if(meetings[i][0]>=lastEndTime){
count++;
lastEndTime = meetings[i][1];
}
}
return count;
}
Arrays.sort(meetings, (a, b) -> a[1] - b[1]);
Arrays.sort()에 2차원 배열을 전달하면, 정렬 알고리즘 내부적으로 요소 2개(a, b)를 꺼내 서로 비교하는 작업을 반복한다.
이때 비교 기준을 전달하기 위해 Comparator의 compare 메서드를 람다식 형태 (a, b) -> ...로 정의한다. (Comparator에 대해서 더 알아볼 필요가 있겠다)
meetings는 int[][] 타입이므로, 여기서 원소를 하나 꺼내면 그 원소의 타입은 자연스럽게 int[] 1차원 배열이 된다.
컴파일러가 문맥(Context)을 통해 a와 b가 int[]임을 알아서 추론하므로 (int[] a, int[] b)처럼 타입을 명시하지 않고 (a, b)만 적어도 a[1], b[1]과 같은 배열 인덱스 접근이 가능하다.
-> 2차원 배열은 각 원소마다 배열을 품고있으니까 한 원소를 읽으면 그 원소는 1차원 배열이니까
a[1] - b[1]의 결과에 따라 정렬 순서가 결정된다.
음수 (a[1] < b[1]): a가 더 일찍 종료되므로 앞에 위치한다.
0 (a[1] == b[1]): 순서를 유지한다.
양수 (a[1] > b[1]): b가 더 일찍 종료되므로 b를 앞으로 이동시킨다.
// 기존 익명 클래스 방식
Arrays.sort(meetings, new Comparator<int[]>() {
@Override
public int compare(int[] a, int[] b) {
return a[1] - b[1];
}
});
익명 클래스 :
파라미터로 새로운 Comparator 객체를 전달하는데 이는 compare를 오버라이드 해서 전달해주는 방식이다. compare라는 Comparator.java파일에 있는 함수형 인터페이스이다.
@FunctionalInterface
public interface Comparator<T> {
// 두 객체를 비교하는 핵심 추상 메서드
int compare(T o1, T o2);
}
따라서 Override로 메서드를 우리가 원하는대로 재정의할 수 있다 여기서는 두 배열을 인자로 받아와서 두 배열의 특정 원소값의 차를 구한다.
// 람다식 적용 (타입 추론 덕분에 간결화)
Arrays.sort(meetings, (a, b) -> a[1] - b[1]);
람다식:
함수형 인터페이스를 간결한 함수 표현식으로 작성
람다식은 Comparator 인터페이스에 메서드가 compare 딱 하나밖에 없기 때문에, 메서드 이름(compare)조차 생략하고 알맹이 구현부((a, b) -> a[1] - b[1])만 적어주는 것이다.
추상 메서드 (Abstract Method)
구현부({ })가 없이 선언만 되어 있어, "나중에 누군가 완성해야 하는 메서드(함수)"입니다.
ex) int compare(T o1, T o2);
함수형 인터페이스 (Functional Interface)
"추상 메서드를 딱 1개만 가지고 있는 인터페이스"입니다.
추상 메서드가 딱 1개만 있기 때문에 자바 컴파일러가 람다식((a, b) -> a[1] - b[1])을 봤을 때 "아, 저 람다식은 저 하나뿐인 추상 메서드를 구현한 거구나!" 하고 1:1로 매핑할 수 있습니다.
그럼 sort에 대해서 좀 더 알아보자
public static <T> void sort(T[] a, Comparator<? super T> c) {
if (c == null) {
sort(a);
} else {
if (LegacyMergeSort.userRequested)
legacyMergeSort(a, c);
else
TimSort.sort(a, 0, a.length, c, null, 0, 0);
}
}
Arrays.sort의 파라미터로는 배열과 정렬 기준인 Comparator가 들어간다.
우리는 인자로 2차원 배열(int[][])과 람다식을 전달해주었다.
Comparator는 자바의 함수형 인터페이스이고, 그 내부에 compare라는 단 하나의 추상 메서드를 가지고 있다.
원래는 Comparator 인터페이스를 구현하는 익명 클래스를 만들고 compare 메서드를 오버라이딩하여 정렬 기준을 넘겨주어야 하지만, 자바 8부터는 이를 한 줄의 람다식으로 간결하게 대체할 수 있다.
이때 meetings가 int[][]이므로, 원소 하나는 int[]가 된다. 자바 컴파일러는 이 문맥을 바탕으로 람다식의 파라미터 (a, b)가 int[] 타입임을 스스로 추론(Type Inference)한다.