배열 자료형
배열은 연관된 data를 메모리상에 연속적이며 순차적으로 미리 할당된 크기만큼 저장하는 자료구조 이다.
배열은 하나의 블록안에 여러 데이터들을 모아 집합시켜 저장함으로써 데이터를 구조적으로 다루는 것을 돕는다. 배열을 구성하는 각각의 값을 배열 요소(element)라고 하며, 배열에서의 위치를 가리키는 숫자를 인덱스(index)라고 칭한다.
배열의 특징
- 고정된 저장 공간(fixed-size)
- 순차적인 데이터 저장(order)
Array의 장점은 lookup과 append가 빠르다는 것이다. 따라서 조회를 자주 해야되는 작업에서는 Array 자료구조를 많이 사용한다.
Array의 단점은 fixed-size 특성상 선언 시에 Array의 크기를 미리 정해야 된다는 것이다. 이는 메모리 낭비나 추가적인 overhead가 발생할 수 있다.
시간복잡도
Array | |
access | O(1) |
append | O(1) |
마지막 원소 delete | O(1) |
insertion | O(n) |
deletion | O(n) |
search | O(n) |
배열 선언 & 초기화
자바(Java)의 배열은 코드를 보면 알 수 있듯이 배열을 선언할때 미리 공간의 갯수(길이)를 지정해야 한다.
이는 곧 공간의 제약이 생겨 데이터를 저장하는데 애로사항이 있을 수 있다는 뜻이기도 하다.
자바스크립트나 파이썬의 배열 같은 경우 유기적으로 늘어나는 특성 때문에 배열에 데이터를 저장하는데 있어 공간을 따진적이 없었기 때문에 적응이 힘들 수도 있다. 하지만 사실 자바스크립트의 배열도 공간의 제약이 있으며 단지 프로그래밍 하기 편하게 내부적으로 배열을 늘였다 줄였다 자동으로 해주기 때문에 못느끼는 것일 뿐이다.
단지 자바는 수동으로 해줘야 한다는 차이점만 있다.
이처럼 배열의 길이는 고정되도록 프로그래밍 상에서 설계 되었기 때문에 만일 배열의 길이를 처음부터 지정하지 않으면 컴파일 오류가 발생하게 된다. 그리고 배열의 타입(int)도 지정해 주어 배열에 저장할 데이터의 자료형을 명시해 주어야 한다.
이렇게 생성한 배열은 인덱스(index) 번호를 통해 접근 할 수 있다.
// int 형 배열 선언 & 초기화
int[] score = new int[5]; // int 타입의 값 5개가 저장될 빈 공간 생성
score[0] = 10; // 각 빈공간에 값을 초기화
score[1] = 20;
score[2] = 30;
score[3] = 40;
score[4] = 50;
// for문으로 배열을 순차적으로 순회에 값을 넣어주는 방법도 있다.
for(int i = 0 ; i < score.length ; i++){
number[i] = i * 10;
}
// 처음부터 선언 + 초기화를 한번에 진행
int[] score2 = {10, 20, 30, 40, 50};
// String 형 배열 선언 & 초기화
String[] name = new String[3]; // String 타입의 값 3개가 저장될 빈 공간 생성
name[0] = "wi"; // 각 빈공간에 값을 초기화
name[1] = "kim";
name[2] = "park"
// 처음부터 선언 + 초기화를 한번에 진행
String[] strArr2 = {"wi", "kim", "park"};
다만 자바에서 배열을 선언하는 것은 단지 배열을 다루기 위한 참조변수를 위해 공간을 만드는 것일 뿐이므로, 메모리에 실제 값을 저장할 수 있는 공간을 만들기 위해서는 new 연산자와 함께 배열을 생성해야 한다.
배열을 생성할 때엔 괄호[] 안에 배열의 길이, 즉 해당 배열에 값을 얼마만큼 저장할 수 있는지를 적어준다. 배열의 길이는 0이 될 수도 있다. 자바에서는 JVM이 모든 배열의 길이를 별도로 관리하며, 배열명.length를 통해서 배열의 길이를 알아낼 수 있다.
앞서 배열은 정적 리스트(static list)라고 하였다. 한번 생성된 배열의 길이는 변경할 수 없기 때문이다. 배열에 저장할 공간이 부족할 경우 더 큰 길이의 배열을 생성한 후 기존 배열의 값을 복사할 수 있다. 이때 System클래스의 arraycopy() 메소드를 사용할 수 있다. System.arraycopy()는 지정된 범위의 값들을 한번에 통째로 복사하는 기능을 제공한다.
메모리 할당
배열에 데이터를 넣기위해서는 메모리를 할당해주어야 하는데 new 연산자를 보면 예상할 수 있다시피 실제 값을 저장할 수 있는 메모리는 heap영역에 생성된다.
new연산자를 사용하게 되면 heap영역에 실제 데이터를 저장할 수 있는 메모리를 생성하게되고 위의 경우 그 메모리는 각각 int형 메모리이다. 메모리 할당 시 대괄호안의 인자는 메모리의 크기(갯수)가 된다.
이후 heap영역에 생성된 int형 메모리는 고유의 주소를 가지게 되고 그 주소를 arrNum이라는 Stack영역에 생성된 메모리에 담기게 된다.
이때 arrNum은 주소를 통해 heap영역의 메모리를 '참조(reference)한다' 라고 한다.
이후 아래와 같이 코드를 찍어보면
아래와 같은 고유의 주소가 arrNum에 저장된 것을 볼 수 있다.
▲ 대괄호로 시작하는 것은 배열을 뜻하고 I는 int형, @는 at 으로 뒤의 나머지 주소를 참조한다는 뜻이다.
이제 배열의 선언과 메모리 힐당까지 했으면 heap영역의 메모리에 있는 데이터 값으로 0이 저장되어 있을 것이다. 왜냐하면 배열은 초기화를 하지 않아도 해당 자료형의 기본값으로 설정이 되기 때문이다. 위에서 우리는 자료형으로 int를 사용했으니 기본값으로 0이 저장되어 있다.
배열 출력
프로그래밍 도중 만일 내가 만든 배열의 상태를 보기 위해 콘솔에 배열 내용물을 출력하고 싶을 때 어떻게 할까?
지금까지 변수를 출력 하듯이 System.out.println() 으로 배열 변수를 출력해보면 이상한 값이 출력되게 된다.
int[] iArr = {100, 95, 80, 70, 60};
System.out.println(iArr); // [I@7ad041f3
// [I : 배열 integer
// @7ad041f3 : 주소값
사실 이 값은 메모리에 있는 배열의 주소값(타입@주소)을 가리키는 것이다.
자바스크립트 처럼 console.log() 로 간편하게 출력하면 좋겠지만 자바의 언어 설계 상 어쩔수 없다.
따라서 for 문을 이용해서 배열 각 원소들을 순회하여 출력하도록 하드코딩 해주거나, 아니면 자바에서 제공해주는 Arrays.toString() 메서드를 이용해서 배열을 문자열 형식으로 만들어 출력할 수도 있다.
import java.util.Arrays; // Arrays.toString()을 사용하기 위한 import
class Test{
public static void main(String[] args) {
int[] iArr = {100, 95, 80, 70, 60};
// 루프문으로 직접 배열 원소 출력
for(int i = 0 ; i < iArr.length; i++){
System.out.println(iArr[i]);
}
// Arrays.toString() 메서드 사용하여 심플하게 바로 출력
System.out.println(Arrays.toString(iArr)); // [100, 95, 80, 70, 60]
}
}
다만 char 형 배열은 예외인데, 문자 같은 경우 println으로 바로 출력이 가능하다.
String 배열
String 배열은 다음과 같이 생성할 수 있다.
단, String은 클래스이므로 String 배열과 같은 참조형 배열, 즉 객체배열의 경우 배열에 저장되는 것은 실제 객체가 아닌 객체의 주소이다.
참고로 모든 참조변수에는 메모리에 저장된 객체의 주소(4byte의 정수값)혹은 null이 저장된다.
Char 배열
문자열 String은 문자 배열인 Char배열과 같은 뜻으로 볼 수 있다. 그런데 자바에서 Char 배열이 아닌 String 클래스를 사용해서 문자열을 다루는 이유는 String 클래스 자체가 Char 배열에 여러 가지 기능(함수, 메서드)을 추가하여 확장한 것이기 때문이다.
단, Char 배열과 달리 String 객체는 읽을 수만 있을 뿐 내용을 변경할 수는 없다. (불변객체)
이는 Java docs에서도 확인할 수 있다. String 클래스 앞에 final 제어자가 붙어있다.
사례를 통해 확인하자.
위 사례에서 str 변수에 담겨있던 “Java is Fun!”이라는 값이 “I hate Java!”로 바뀌었을까?
답은 ‘그렇지 않다’ 이다. String 객체에 값을 저장할 때마다 새로운 String 객체가 생성될 뿐이다.
이런 식으로 계속 String 객체를 생성하는 것은 메모리 차원에서도 비효율적이고, 사용하지 않는 String 객체를 계속 제거해야 하는 JVM에도 부하가 될 수 있다.
이러한 점을 보완하기 위해 StringBuffer 혹은 StringBuilder클래스를 사용할 수 있다. 이와 관련한 내용은 따로 다룰 것이다.
배열 복사
앞서 배열은 고정된 크기라고 했었다.
그런데 배열을 만들고 나서 데이터를 적재하다보니 배열 공간이 부족해질수 있는 상황이 올 수 도 있다.
그러면 배열을 확장 시켜주어야 하는데 어떻게 해결을 해야 할까?
배열은 한번 선언되고 나면 공간 자체를 직접 늘릴수는 없기 때문에 간접적인 방법으로 배열을 확장해야 된다.
따로 공간이 큰 배열을 새로 만들어 주고 기존의 배열의 내용을 새로 만든 배열에 복사하는 식으로 하여 배열을 간접적으로 확장하는 방법이다.
다만, 이러한 작업은 비용이 많이 들기 때문에 처음부터 배열의 길이를 넉넉하게 잡는 것이 베스트이다.
배열을 복사하는 방법은 for문으로 순회해 직접 한땀 한땀 복사하도록 지정해주거나, 자바에서 제공해주는 System.arraycopy() 메서드나 Arrays.copyOf() 메서드를 사용하면 된다.
※ 참고
Arrays.copyOf는 System.arraycopy를 래핑한 함수일뿐이다. 즉, 둘이 동일하다고 보면된다.
다만 Arrays.copyOf 가 좀더 직관적이라 이쪽이 더 많이 사용되는 편이다
import java.util.Arrays;
class Test{
public static void main(String[] args) {
int[] arr1 = {10, 20, 30, 40, 50};
int[] arr2 = new int[arr1.length * 2]; // 우선 초기 배열보다 길이가 두배인 새로운 배열을 선언
// 루프문으로 순회하여 복사
for(int i = 0 ; i < arr1.length ; i++) { // arr1의 길이만큼 반복문 실행
arr2[i] = arr1[i]; // arr1배열의 원소값을 순회하며 arr2배열에 저장
}
arr1 = arr2; // 원래의 배열을 가리키고있던 참조변수 arr1이 새로 복사된 arr2 배열을 가리키도록 한다.
}
}
class Test{
public static void main(String[] args) {
int[] arr1 = {10, 20, 30, 40, 50};
int[] arr2 = new int[arr1.length * 2]; // 우선 초기 배열보다 길이가 두배인 새로운 배열을 선언
// System.arraycopy() 메서드 사용
System.arraycopy(arr1, 0, arr2, 0, arr1.length); // arr1의 index 0부터 arr1.length 전체 길이 만큼 arr2의 index 0 부터 붙여넣는다.
/*
- 첫번째 인자 : 복사할 배열
- 두번째 인자 : 복사를 시작할 배열의 위치
- 세번째 인자 : 붙여넣을 배열
- 네번째 인자 : 복사된 배열값들이 붙여질 시작위치 (차례대로 붙여 넣어진다)
- 다섯번째 인자 : 지정된 길이만큼 값들이 복사된다.
*/
}
}
import java.util.Arrays;
class Test{
public static void main(String[] args) {
int[] arr1 = {10, 20, 30, 40, 50};
int[] arr2 = new int[arr1.length * 2]; // 우선 초기 배열보다 길이가 두배인 새로운 배열을 선언
// Array.copyOf() 메서드 사용
arr2 = Arrays.copyOf(arr1, arr1.length); // arr1 배열을 arr1.length 전체 길이만큼 전체 복사해서 arr2에 할당
System.out.println(Arrays.toString(arr2)); // [10, 20, 30, 40, 50]
arr2 = Arrays.copyOfRange(arr1, 1, 3); // 배열요소 시작점, 끝점 지정. 1, 2 만 복사해서 반환
System.out.println(Arrays.toString(arr2)); // [20, 30]
}
}
※ 참고
for문 보다 메서드를 이용하는게 거의 두배 정도로 빠르게 복사한다고 한다
배열 정렬
Arrays.sort() 메서드를 이용해 배열을 정렬할 수 있다.
이때 정렬된 배열을 새로 반환하는 것이 아닌, 자기 자신 배열을 정렬시킨다.
import java.util.Arrays;
class Test{
public static void main(String[] args) {
int[] arr = { 3,2,0,1,4 };
// 오름차순 정렬
Arrays.sort(arr); // 자기 자신 배열을 정렬 시킴 (정렬된 배열을 반환하는 것이 아니다)
System.out.println(Arrays.toString(arr)); // [0,1,2,3,4]
// 내림차순 정렬
Arrays.sort(arr, Collections.reverseOrder()); // 배열을 내림차순으로 정렬할 때는 Collections 클래스의 reverseOrder() 함수를 사용
System.out.println(Arrays.toString(arr)); // [4,3,2,1,0]
// 배열 일부부만 정렬
int[] arr = { 3,2,0,1,4 };
Arrays.sort(arr, 0, 3); // 배열 요소 0, 1, 2 만 정렬
System.out.println(Arrays.toString(arr)); // [0, 2, 3, 1, 4]
}
}
배열 비교
만일 두개의 배열의 구성이 같은지 같지 않은지 비교하기 위해서 일일히 for문으로 순회하여 원소를 비교하는 식으로도 구현을 할 수 있지만, 하지만 역시 Arrays.equals() 메소드를 이용하면 간단히 처리할 수 있다
import java.util.Arrays;
public class Main {
public static void main(String[] args) {
String[] arr1 = { "홍길동", "임꺽정", "박혁거세", "주몽", "고담덕" };
String[] arr2 = { "홍길동", "임꺽정", "박혁거세", "주몽", "고담덕" };
String[] arr3 = { "홍길동", "임꺽정", "박혁거세", "주몽" };
System.out.println("arr1 == arr2 : " + Arrays.equals(arr1, arr2)); // arr1 == arr2 : true
System.out.println("arr1 == arr3 : " + Arrays.equals(arr1, arr3)); // arr1 == arr3 : false
}
}
객체 배열
보통 배열에 정수나 문자를 적재하여 꺼내 써왔을 것인데, 객체 자체도 배열에 넣어 사용할수 있다.
객체 역시 하나의 자료형으로 취급되기 때문이다.
// myObject 클래스
class myObject{
int id;
String description;
myObject(int id, String description) {
this.id = id;
this.description = description;
}
}
// myObject 클래스를 담을 수 있는 공간 3개 크기의 객체 배열 생성
myObject[] arrayObj = new myObject[3];
// 객체 배열 초기화
arrayObj[0] = new myObject(101, "first");
arrayObj[1] = new myObject(102, "second");
arrayObj[2] = new myObject(103, "third");
// 객체 배열 사용
System.out.println(arrayObj[0].description); // "first array, John"
/* ************************************ */
// 객체 배열 선언 + 초기화 한번에
myObject[] arrayObj2 = {
new myObject(101, "first"),
new myObject(101, "second"),
new myObject(101, "third")
};
먼저 myObject[] arrayObj = new myObject[3] 로 myObject 타입의 배열을 생성해준다.
그리고 각 배열 공간에 new 생성자로 객체를 만들어 할당해 준다.
그러면 비로소 배열에 객체가 적재가 되어 객체 배열로서 사용을 할 수 있는 것이다.
객체 배열 복사
기본 타입의 배열일 경우 Arrays.copyOf 나 Arrays.copyOfRange 메서드를 통하여 간단하게 배열 복사가 가능했다.
객체로 이루어진 배열도 마찬가지로 가능하지만, 여기서 조심해야 할 점이 있다.
배열 자체는 복사가 되지만, 배열 내용물 객체는 참조 복사(주소 복사)가 되기 때문이다.
즉, 배열 내용물은 여전히 같은 객체 주소를 가리키기 때문에 객체도 복사 되었는 줄 알고 복사한 객체의 멤버를 변경하면 복사된 멤버의 객체도 변경되는 꼴이 된다.
class myObject{
int id;
String description;
myObject(int id, String description) {
this.id = id;
this.description = description;
}
}
myObject[] arrayObj = {
new myObject(101, "first"),
new myObject(101, "second"),
new myObject(101, "third")
};
System.out.println(Arrays.toString(arrayObj)); // [main$1myObject@251a69d7, main$1myObject@7344699f, main$1myObject@6b95977]
myObject[] arrayObj2; // 복사할 배열
arrayObj2 = arrayObj.clone(); // 배열을 복사해도 내용물 객체의 주소는 똑같다.
System.out.println(Arrays.toString(arrayObj2)); // [main$1myObject@251a69d7, main$1myObject@7344699f, main$1myObject@6b95977]
System.out.println(arrayObj[0].id); // 101
arrayObj2[0].id = 999; // 복사한 arrayObj2의 첫째 객체의 멤버를 변경
System.out.println(arrayObj2[0].id); // 999
System.out.println(arrayObj[0].id); // 999 : arrayObj1 의 첫째 겍체의 멤버도 변경됨
따라서 완전한 깊은 복사를 이행하기 위해서는 어쩔수 없이 for문으로 수동으로 해주는 수 밖에 없다.
class myObject{
int id;
String description;
myObject(int id, String description) {
this.id = id;
this.description = description;
}
}
myObject[] arrayObj = {
new myObject(101, "first"),
new myObject(102, "second"),
new myObject(103, "third")
};
System.out.println(Arrays.toString(arrayObj)); // [main$1myObject@251a69d7, main$1myObject@7344699f, main$1myObject@6b95977]
myObject[] arrayObj2 = new myObject[3];
for(int i = 0; i < arrayObj.length; i++) {
arrayObj2[i] = new myObject(arrayObj[i].id, arrayObj[i].description);
}
// 배열 내용물 객체의 @주소가 달라짐을 볼 수 있다.
System.out.println(Arrays.toString(arrayObj2)); // [main$1myObject@7e9e5f8a, main$1myObject@8bcc55f, main$1myObject@58644d46]
System.out.println(arrayObj[0].id); // 101
arrayObj2[0].id = 999; // 복사한 arrayObj2의 첫째 객체의 멤버를 변경
System.out.println(arrayObj2[0].id); // 999
System.out.println(arrayObj[0].id); // 101
객체 배열 정렬
다음과 같이 이름과 나이 데이터를 갖는 User 객체 배열이 있다. 이 배열 내의 객체들을 정렬하기 위해서는 정렬 기준이 필요한데 name 을 이용해 이름순으로 정렬할 수도 있고, age 를 이용해 나이순으로 정렬할 수 도 있다.
import java.util.*;
public class main {
public static void main(String[] args) {
class User {
String name;
int age;
User(String name, int price) {
this.name = name;
this.price = price;
}
}
User[] users = {
new User("홍길동", 32),
new User("김춘추", 64),
new User("임꺽정", 48),
new User("박혁거세", 14),
}
}
}
객체 배열을 정렬하기 위해서는 꽤나 고급 지식들이 요구된다. 이 포스팅에서는 Comparable 인터페이스 와 Comparator 클래스를 이용한 객체 배열 정렬 방법을 간단히 소개해본다.
Comparable 인터페이스 사용
자바에서는 같은 타입의 인스턴스를 서로 비교해야 할때 Comparable 인터페이스를 구현해서 compareTo() 메소드를 오버라이딩 정의하고 사용한다.
기본 타입은 물론 Boolean을 제외한 래퍼 클래스나 String, Time, Date와 같은 클래스의 인스턴스는 모두 정렬 가능하다.
import java.util.Arrays;
// 클래스에 Comparable<> 인터페이스를 구현한다
class User implements Comparable<User> {
String name;
int age;
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 0;
} else {
return 1;
}
}
}
public class main {
public static void main(String[] args) {
User[] users = {
new User("홍길동", 32),
new User("김춘추", 64),
new User("임꺽정", 48),
new User("박혁거세", 14),
};
Arrays.sort(users); // 나이순 정렬
// Arrays.sort(users, Collections.reverseOrder()); // 역순 정렬
for (User u : users) { // 출력
System.out.println(u.name + " " + u.age + "세");
}
}
}
박혁거세 14세
홍길동 32세
임꺽정 48세
김춘추 64세
Comparator 클래스 사용
Comparator 클래스도 Comparable 인터페이스와 같이 객체를 정렬하는 데 사용되는 클래스 이다.
다만 익명 객체를 이용해 좀더 유기적으로 다양하게 속성을 받아 정렬할 수 있어서 좀 더 간편하게 객체 비교 정렬이 가능하다.
import java.util.Arrays;
import java.util.Comparator; // Comparator 클래스를 불러온다
class User {
String name;
int age;
User(String name, int age) {
this.name = name;
this.age = age;
}
}
public class main {
public static void main(String[] args) {
User[] users = {
new User("홍길동", 32),
new User("김춘추", 64),
new User("임꺽정", 48),
new User("박혁거세", 14),
};
// Arrays.sort(배열, new Comparator<>() { ... });
Arrays.sort(users, new Comparator<User>() {
@Override
public int compare(User u1, User u2) {
return Integer.compare(u1.age, u2.age); // Integer 클래스에 정의된 compare 함수로 두 가격 정수 원시값을 비교
}
});
// java8 람다식으로 다음과 같이 축약이 가능
Arrays.sort(users, (u1, u2) -> Integer.compare(u1.age, u2.age)); // 나이순 정렬
// 출력
for (User u : users) {
System.out.println(u.name + " " + u.age + "세");
}
}
}
박혁거세 14세
홍길동 32세
임꺽정 48세
김춘추 64세
만일 나이순이 아닌 이름(문자열)순으로 정렬하려면 compare() 대신 compareTo() 메서드로 가능하다.
import java.util.Arrays;
import java.util.Comparator; // Comparator 클래스를 불러온다
class User {
String name;
int age;
User(String name, int age) {
this.name = name;
this.age = age;
}
}
public class main {
public static void main(String[] args) {
User[] users = {
new User("홍길동", 32),
new User("김춘추", 64),
new User("임꺽정", 48),
new User("박혁거세", 14),
};
// Arrays.sort(배열, new Comparator<>() { ... });
Arrays.sort(users, new Comparator<User>() {
@Override
public int compare(User u1, User u2) {
return u1.name.compareTo(u2.name);
}
});
// java8 람다식으로 다음과 같이 축약이 가능
Arrays.sort(users, (u1, u2) -> u1.name.compareTo(u2.name)); // 이름순 정렬
// 출력
for (User u : users) {
System.out.println(u.name + " " + u.age + "세");
}
}
}
김춘추 64세
박혁거세 14세
임꺽정 48세
홍길동 32세
여러 조건 비교 (comparing / thenComparing)
만약 나이순으로 정렬했는데 나이가 같은 사람이 있을 경우 추가적으로 이름순으로 정렬해줄 필요가 있을 것이다.
즉, 객체의 여러 속성을 이용하여 정렬하기 위해 Comparator의 comparing() 과 thenComparing() 을 이용해 체이닝하여 구현이 가능하다.
이때 객체의 속성을 가져올때 getter / setter을 이용해 가져와주어야 한다.
import java.util.Arrays;
import java.util.Comparator;
class User {
private String name;
private int age;
User(String name, int age) {
this.name = name;
this.age = age;
}
public int getAge() {
return this.age;
}
public String getName() {
return this.name;
}
}
public class main {
public static void main(String[] args) {
User[] users = {
new User("홍길동", 30),
new User("김춘추", 60),
new User("임꺽정", 30),
new User("김좌진", 20),
new User("주몽", 50),
new User("심사임당", 30),
};
// 나이순 정렬
Arrays.sort(users, Comparator.comparing(User::getAge));
for (User u : users) { System.out.println(u.name + " " + u.age + "세"); }
System.out.println("\n");
// 이름순 정렬
Arrays.sort(users, Comparator.comparing(User::getName));
for (User u : users) { System.out.println(u.name + " " + u.age + "세"); }
System.out.println("\n");
// 먼저 나이순 정렬하고 나이가 같으면 따로 이름순 정렬
Arrays.sort(users, Comparator.comparing(User::getAge).thenComparing(User::getName));
for (User u : users) { System.out.println(u.name + " " + u.age + "세"); }
}
}
김좌진 20세
홍길동 30세
임꺽정 30세
심사임당 30세
주몽 50세
김춘추 60세
김좌진 20세
김춘추 60세
심사임당 30세
임꺽정 30세
주몽 50세
홍길동 30세
김좌진 20세
심사임당 30세
임꺽정 30세
홍길동 30세
주몽 50세
김춘추 60세
참고
- https://medium.com/@lunay0ung/java-array-feat-string-vs-char-fea4875fc7ec
- https://itworldyo.tistory.com/119
- https://inpa.tistory.com/entry/JAVA-%E2%98%95-%EC%9E%90%EB%B0%94-%EB%B0%B0%EC%97%B4Array-%EB%AC%B8%EB%B2%95-%EC%9D%91%EC%9A%A9-%EC%B4%9D%EC%A0%95%EB%A6%AC#%EA%B0%80%EB%B3%80_%EB%B0%B0%EC%97%B4