| 일 | 월 | 화 | 수 | 목 | 금 | 토 |
|---|---|---|---|---|---|---|
| 1 | 2 | 3 | ||||
| 4 | 5 | 6 | 7 | 8 | 9 | 10 |
| 11 | 12 | 13 | 14 | 15 | 16 | 17 |
| 18 | 19 | 20 | 21 | 22 | 23 | 24 |
| 25 | 26 | 27 | 28 | 29 | 30 | 31 |
- 알고리즘
- 예외처리
- 클린코드
- HashMap
- 자바개발
- 프로그래머스
- 코딩인터뷰
- Java
- 객체지향
- 개발공부
- 정렬
- 개발자팁
- 자바기초
- 가비지컬렉션
- 코딩테스트팁
- 백준
- 파이썬
- 자바
- 자바프로그래밍
- 프로그래밍기초
- 코딩테스트준비
- 개발자취업
- 자료구조
- 자바공부
- 알고리즘공부
- JVM
- 멀티스레드
- 코딩공부
- 메모리관리
- 코딩테스트
- Today
- Total
코드 한 줄의 기록
Java 배열(1차원/다차원)과 Arrays 유틸리티 완벽 정리: 초보자부터 실무까지 한 번에! 본문
배열은 자바 프로그래밍의 기초 중의 기초라고 할 수 있습니다. 처음 배울 때는 단순해 보이지만, 실제로 활용하다 보면 정말 많은 기능과 메서드들이 있다는 걸 깨닫게 되죠.
이번 글에서는 Java의 1차원/다차원 배열부터 Arrays 클래스의 유용한 메서드들까지 차근차근 살펴보겠습니다. 같이 공부하는 마음으로 준비했으니 천천히 따라와 주세요!
1차원 배열 기초부터 탄탄하게
배열 선언의 세 가지 방법
자바에서 배열을 선언하는 방법은 생각보다 다양합니다.
// 방법 1: 타입 옆에 대괄호
int[] numbers;
// 방법 2: 배열명 앞에 대괄호 (공백 있음)
int []scores;
// 방법 3: 배열명 뒤에 대괄호 (C언어 스타일)
int grades[];
개인적으로는 첫 번째 방법을 선호합니다. 타입을 보면 바로 '아, 이건 배열이구나'라는 걸 알 수 있거든요.
배열 초기화 방법들
배열을 초기화하는 방법도 여러 가지가 있습니다.
// 1. 크기만 지정 (기본값으로 초기화)
int[] arr1 = new int[5]; // [0, 0, 0, 0, 0]
// 2. 선언과 동시에 값 설정
int[] arr2 = {1, 2, 3, 4, 5};
// 3. new 키워드와 함께 값 설정
int[] arr3 = new int[]{10, 20, 30};
// 4. 반복문으로 초기화
int[] arr4 = new int[5];
for(int i = 0; i < arr4.length; i++) {
arr4[i] = i * 2; // [0, 2, 4, 6, 8]
}
배열 출력하기
배열을 출력할 때 흔히 하는 실수가 있습니다.
int[] numbers = {1, 2, 3, 4, 5};
// 잘못된 방법 - 이상한 값이 출력됨
System.out.println(numbers); // [I@15db9742 같은 해시코드
// 올바른 방법 - Arrays.toString() 사용
System.out.println(Arrays.toString(numbers)); // [1, 2, 3, 4, 5]
처음에 저도 이 부분에서 당황했던 기억이 나네요. 배열 자체를 출력하면 메모리 주소가 나오니까 반드시 Arrays.toString()을 사용해야 합니다.
다차원 배열 정복하기
2차원 배열의 이해
2차원 배열은 '배열의 배열'이라고 생각하면 됩니다. 게임에서 맵을 표현하거나 표 형태의 데이터를 다룰 때 정말 유용하죠.
// 2차원 배열 선언 및 초기화
int[][] matrix = new int[3][4]; // 3행 4열
// 값 설정과 동시에 초기화
int[][] scores = {
{90, 85, 92, 88},
{76, 94, 82, 90},
{88, 79, 95, 87}
};
// 반복문으로 초기화
int[][] table = new int[3][4];
for(int i = 0; i < table.length; i++) {
for(int j = 0; j < table[i].length; j++) {
table[i][j] = (i + 1) * (j + 1);
}
}
여기서 중요한 건 table.length는 행의 개수를, table[i].length는 각 행의 열 개수를 나타낸다는 점입니다.
비정방형 배열의 활용
자바의 특별한 기능 중 하나가 바로 비정방형 배열입니다. 각 행마다 열의 개수가 다를 수 있어서 메모리를 효율적으로 사용할 수 있죠.
// 비정방형 배열 생성
int[][] irregular = new int[4][];
irregular[0] = new int[1]; // 첫 번째 행: 1개 열
irregular[1] = new int[3]; // 두 번째 행: 3개 열
irregular[2] = new int[2]; // 세 번째 행: 2개 열
irregular[3] = new int[4]; // 네 번째 행: 4개 열
// 생성과 동시에 초기화
int[][] triangle = {
{1},
{1, 2},
{1, 2, 3},
{1, 2, 3, 4}
};
3차원 배열과 그 이상
3차원 배열도 가능하지만, 실제로는 특별한 경우가 아니면 잘 사용하지 않습니다.
// 3차원 배열 - 2x3x4 크기
int[][][] cube = new int[2][3][4];
// 값 설정
for(int i = 0; i < cube.length; i++) {
for(int j = 0; j < cube[i].length; j++) {
for(int k = 0; k < cube[i][j].length; k++) {
cube[i][j][k] = i + j + k;
}
}
}
Arrays 클래스: 배열의 만능 도구
java.util.Arrays 클래스는 배열을 다루는 데 필요한 거의 모든 기능을 제공합니다. 모든 메서드가 static이라서 객체 생성 없이 바로 사용할 수 있어요.
배열 정렬과 검색
가장 많이 사용하는 기능 중 하나가 정렬입니다.
int[] numbers = {5, 2, 8, 1, 9, 3};
// 오름차순 정렬
Arrays.sort(numbers);
System.out.println(Arrays.toString(numbers)); // [1, 2, 3, 5, 8, 9]
// 이진 검색 (정렬된 배열에서만 사용!)
int index = Arrays.binarySearch(numbers, 5);
System.out.println("5의 인덱스: " + index); // 3
주의할 점: binarySearch()는 반드시 정렬된 배열에서만 사용해야 합니다. 정렬되지 않은 배열에서 사용하면 잘못된 결과가 나올 수 있어요.
배열 복사의 다양한 방법
int[] original = {1, 2, 3, 4, 5};
// 전체 복사
int[] copy1 = Arrays.copyOf(original, original.length);
// 일부만 복사
int[] copy2 = Arrays.copyOf(original, 3); // [1, 2, 3]
// 크기를 늘려서 복사 (빈 공간은 0으로 채워짐)
int[] copy3 = Arrays.copyOf(original, 7); // [1, 2, 3, 4, 5, 0, 0]
// 범위 지정 복사
int[] copy4 = Arrays.copyOfRange(original, 1, 4); // [2, 3, 4]
배열 채우기와 비교
// 배열을 특정 값으로 채우기
int[] arr = new int[5];
Arrays.fill(arr, 10); // [10, 10, 10, 10, 10]
// 람다식으로 채우기
Arrays.setAll(arr, i -> i * 2); // [0, 2, 4, 6, 8]
// 배열 비교
int[] arr1 = {1, 2, 3};
int[] arr2 = {1, 2, 3};
boolean isEqual = Arrays.equals(arr1, arr2); // true
다차원 배열을 위한 특별 메서드
int[][] matrix1 = {{1, 2}, {3, 4}};
int[][] matrix2 = {{1, 2}, {3, 4}};
// 다차원 배열 비교
boolean isEqual = Arrays.deepEquals(matrix1, matrix2); // true
// 다차원 배열 출력
System.out.println(Arrays.deepToString(matrix1)); // [[1, 2], [3, 4]]
일반 equals()나 toString()은 다차원 배열에서 제대로 작동하지 않으니 반드시 deep 버전을 사용해야 합니다.
실무에서 자주 쓰는 배열 패턴들
배열과 List 변환
실무에서는 배열과 List를 자주 변환해야 합니다.
// 배열을 List로 변환
Integer[] intArray = {1, 2, 3, 4, 5};
List<Integer> list = Arrays.asList(intArray);
// 주의: 이렇게 만든 List는 크기가 고정됨!
// list.add(6); // UnsupportedOperationException 발생
// 가변 List가 필요하면 새로 생성
List<Integer> mutableList = new ArrayList<>(Arrays.asList(intArray));
배열 크기 조정 패턴
public class DynamicArray {
private int[] array;
private int size;
public DynamicArray(int initialCapacity) {
array = new int[initialCapacity];
size = 0;
}
public void add(int value) {
if (size >= array.length) {
// 배열 크기 두 배로 확장
array = Arrays.copyOf(array, array.length * 2);
}
array[size++] = value;
}
public int[] toArray() {
return Arrays.copyOf(array, size);
}
}
2차원 배열 순회 최적화
int[][] matrix = new int[1000][1000];
// 일반적인 순회
for(int i = 0; i < matrix.length; i++) {
for(int j = 0; j < matrix[i].length; j++) {
matrix[i][j] = i * j;
}
}
// 향상된 for문 활용
for(int[] row : matrix) {
Arrays.fill(row, 5); // 모든 요소를 5로 설정
}
성능과 메모리 고려사항
배열 vs ArrayList 선택 기준
배열과 ArrayList 중 어떤 걸 선택할지는 늘 고민되는 부분입니다.
| 배열을 선택하는 경우 | ArrayList를 선택하는 경우 |
| 크기가 고정되어 있을 때 | 크기가 동적으로 변경될 때 |
| 메모리 사용량을 최소화하고 싶을 때 | 편리한 메서드들이 필요할 때 |
| 원시 타입(int, double 등)을 저장할 때 | 객체 타입을 저장할 때 |
| 성능이 중요한 경우 | 객체 타입을 저장할 때 |
메모리 효율적인 배열 사용법
// 메모리 효율적인 초기화
int[] largeArray = new int[1000000];
Arrays.fill(largeArray, 0); // 명시적으로 0으로 초기화
// 불필요한 복사 피하기
public void processArray(int[] arr) {
// 원본 배열 직접 수정 (복사하지 않음)
for(int i = 0; i < arr.length; i++) {
arr[i] *= 2;
}
}
실제 코딩에서 유용한 팁들
배열 디버깅 꿀팁
public static void printArrayInfo(int[] arr, String name) {
System.out.println(name + " 정보:");
System.out.println("- 길이: " + arr.length);
System.out.println("- 내용: " + Arrays.toString(arr));
System.out.println("- 해시코드: " + arr.hashCode());
System.out.println();
}
// 사용 예시
int[] testArray = {1, 2, 3, 4, 5};
printArrayInfo(testArray, "테스트 배열");
예외 상황 처리
public static int safeGetElement(int[] arr, int index) {
if (arr == null) {
throw new IllegalArgumentException("배열이 null입니다.");
}
if (index < 0 || index >= arr.length) {
throw new IndexOutOfBoundsException("인덱스가 범위를 벗어났습니다: " + index);
}
return arr[index];
}
배열 검증 유틸리티
public class ArrayUtils {
public static boolean isEmpty(int[] arr) {
return arr == null || arr.length == 0;
}
public static boolean contains(int[] arr, int value) {
return Arrays.binarySearch(Arrays.copyOf(arr, arr.length), value) >= 0;
}
public static int[] removeElement(int[] arr, int index) {
if (isEmpty(arr) || index < 0 || index >= arr.length) {
return arr;
}
int[] result = new int[arr.length - 1];
System.arraycopy(arr, 0, result, 0, index);
System.arraycopy(arr, index + 1, result, index, arr.length - index - 1);
return result;
}
}
Java의 배열과 Arrays 클래스는 정말 강력한 도구입니다. 처음에는 단순해 보이지만, 깊이 파면 팔수록 다양한 활용법이 나오죠. 특히 실무에서는 성능과 메모리 효율성을 고려한 배열 사용이 중요합니다.
저도 이 글을 정리하면서 다시 한번 배열의 다양한 기능들을 확인할 수 있었어요. 특히 비정방형 배열이나 deepEquals() 같은 메서드들은 알아두면 정말 유용할 것 같습니다.
앞으로 배열을 사용할 때는 단순히 데이터를 저장하는 용도로만 생각하지 말고, Arrays 클래스의 다양한 메서드들을 적극 활용해보세요. 코드가 훨씬 깔끔해지고 효율적이 될 거예요!
'JAVA' 카테고리의 다른 글
| Java 재귀함수 완전정복: 종료조건부터 꼬리재귀까지 실무 개발자가 알려주는 모든 것 (0) | 2025.10.01 |
|---|---|
| Java 메서드 완전 정복: 정의부터 오버로딩, 가변인자까지 한 번에 마스터하기 (0) | 2025.09.30 |
| Java 조건문 완벽 가이드: if vs switch, 그리고 최신 Switch 표현식 패턴 활용법 (0) | 2025.09.27 |
| Java 반복문 완벽 가이드: for·while·do-while 그리고 향상된 for 활용법 (0) | 2025.09.26 |
| [완벽 가이드] Java 연산자 종류와 우선순위 총정리 – 산술·비트·논리·비교·삼항 연산자 (0) | 2025.09.25 |