[JAVA] Arrays 클래스

Van·2023년 5월 24일
0

Arrays

Goal

  • Arrays 클래스를 간략하게 알아보자
  • Arrays 클래스의 대표적인 메소드를 알아보자
  • 각각의 메소드의 사용 방법을 터득한다

Introduction

Arrays 클래스는 JAVA에서 배열 자료구조를 쉽게 사용하게 해주는 제공하는 유틸리티 클래스입니다.
java.util패키지에 구현되어 있으며 Arrays 클래스는 배열을 조작하고 정렬하고 검색하는 등의 기능을 제공하여 배열을 더 편리하게 다룰 수 있습니다.


Arrays.sort

public static <T> T[] sort(T[] arr)
// 주어진 배열 'arr'를 오름차순으로 정렬합니다.
// 배열의 요소는 'Comparable' 인터페이스를 구현해야 합니다.
public static <T> T[] sort(T[] arr, Comparator<? super T> c)
// 주어진 배열 'arr'를 'Comparator' 객체 'c'를 사용하여 정렬합니다.

sort메소드는 배열을 기본적으로 오름차순으로 정렬하며 배열의 값을 ASCII코드 기준으로 정렬합니다.
때문에 배열의 값이 숫자,문자를 구분하지 않고 정렬을 진행할 수 있습니다.

sort메소드에서 중요한 점은 원본 배열을 보장하지 않는다는 점입니다.
즉, 원본 배열 자체를 정렬하기 때문에 원본 배열은 가능하다면 그대로 두고 copyOf메소드를 이용하여 새로운 배열을 만들고 새로 만든 배열을 조작하는 것이 좋습니다. 이는 데이터의 불변성과 연관이 있습니다.

sort 오름차순 예제

import java.util.Arrays;
static void sortAsc() {
    int[] intArr = new int[]{1, 5, 6, 1, 8, 3, 7, 2, 4, 8, 9};
    char[] charArr = new char[]{'q', 'b', 'f', 't', 'e', 'j', 'a'};

    Arrays.sort(intArr);
    // int 정렬
    Arrays.sort(charArr);
    // char 정렬

    System.out.println(Arrays.toString(intArr));
    // 출력 : [1, 1, 2, 3, 4, 5, 6, 7, 8, 8, 9]

    System.out.println(Arrays.toString(charArr));
    // 출력 : [a, b, e, f, j, q, t]
}

위의 예제에서 확인할 수 있는 것처럼 배열의 값들을 Arrays.sort() 메소드로 오름차순으로 정렬이 가능합니다.
하지만 내림차순으로 정렬하려면 비슷하지만 추가적인 과정이 필요합니다.

sort 내림차순 예제

import java.util.Arrays;
import java.util.Comparator;
static void sortDesc() {
    Integer[] intArr = new Integer[]{1, 5, 6, 1, 8, 3, 7, 2, 4, 8, 9};
    Character[] charArr = new Character[]{'q', 'b', 'f', 't', 'e', 'j', 'a'};

    Arrays.sort(intArr, Comparator.reverseOrder());
    // Integer 역순으로 정렬
    Arrays.sort(charArr, new Comparator<Character>() {
        @Override
        public int compare(Character o1, Character o2) {
            return o2 - o1;
        }
    });
    // Character 역순으로 정렬

    System.out.println(Arrays.toString(intArr));
    // 출력 : [9, 8, 8, 7, 6, 5, 4, 3, 2, 1, 1]

    System.out.println(Arrays.toString(charArr));
    // 출력 : [q, b, f, t, e, j, a]
}

위의 예제에서는 Arrays.sort()메소드에 2번째 인자로 Comparator.reverOrder()메소드를 전달하여 내림차순으로 정렬할 수 있습니다.
Comparator는 비교 연산을 위한 인터페이스로 내림차순 정렬을 하기 위한 reverseOrder메소드가 구현되어 있습니다.

또는 Comparator인터페이스의 compare를 구현하여 전달해도 되는데 위에서는 o2 - o1을 전달하여 역순으로 정렬을 하였으며 만약 정순으로 하고 싶다면 o1 - o2를 전달하면 됩니다.

그리고 중요한 점은 원시 타입에는 Comparable이 구현되어 있지 않기 때문에 반드시 원하는 타입의 레퍼(Wrapper) 클래스로 배열을 만들어야 합니다.

public final class Integer extends Number implements Comparable<Integer>

위는 int의 래퍼 클래스 Integer의 선언 부분으로 Comparable을 구현한 것을 확인 할 수 있습니다.


Arrays.binarySearch

public static <T> T[] binarySearch(T[] arr, type key)
// 주어진 배열 'arr'에서 key가 되는 값을 찾아서 반환합니다.
// 존재하면 해당하는 값의 index를 반환, 없다면 음수를 반환합니다.
public static <T> T[] binarySearch(T[] arr, T key, Comparator<? super T> c)
// 또는 Comparator를 전달하여 비교하는 방법을 지정 할 수도 있다

binarySearch메소드는 정렬된 배열에서 이진 검색을 수행하여 특정 요소의 index를 반환합니다.
만약, 정렬되어 있지 않는 배열에서 사용하는 경우에는 올바른 결과를 보장하지 않기 때문에 반드시 sort메소드를 이용하여 정렬한 뒤에 검색해야 합니다.

binarySearch(이진 검색) 동작 방식

  1. 전달된 배열 'array'의 중간 요소를 선택.
  2. 선택한 요소와 'key'값을 비교합니다.
    • 만약 선택한 요소가 'key'와 동일한다면, 해당 요소의 인덱스를 반환합니다.
    • 만약 선택한 요소가 'key'와 작다면, 검색 범위를 현재 요소의 우측 부분 배열로 좁힙니다.
    • 만약 선택한 요소가 'key'와 크다면, 검색 범위를 현재 요소의 좌측 부분 배열로 좁힙니다.
  3. 검색 범위를 좁혀가며 위의 과정을 반복합니다. 검색 범위가 더 이상 좁혀지지 않을 때까지 반복합니다.
  4. 검색 범위가 더 이상 없거나, 'key'를 찾지 못한 경우, -1 또는 -insertionPoint를 반환합니다.

binarySearch 예제

import java.util.Arrays;
public static void binarySearch() {
    int[] intArr = new int[]{1, 5, 2, 4, 6, 3};
    char[] charArr = new char[]{'q', 'b', 'f', 't', 'e', 'j', 'a'};

    // 정렬 하지 않고 출력
    System.out.println(Arrays.binarySearch(intArr, 5));
    // 출력 : -5
    System.out.println(Arrays.binarySearch(charArr, 'q'));
    // 출력 : -4

    // sort메소드를 이용하여 정렬
    Arrays.sort(intArr);
    Arrays.sort(charArr);

    // 정렬 되고 난 후의 출력
    System.out.println(Arrays.binarySearch(intArr, 5));
    // 출력 : 4
    System.out.println(Arrays.binarySearch(charArr, 'q'));
    // 출력 : 5

    // 찾지 못 하는 경우
    System.out.println(Arrays.binarySearch(intArr, 10));
    // 출력 : -7
    System.out.println(Arrays.binarySearch(charArr, 'x'));
    // 출력 : -8
}

위의 예제에서는 Arrays.binarySearch()메소드를 이용하여 key 값으로 전달한 값을 찾습니다.
존재하면 양수를 반환, 존재하지 않는다면 음수를 반환합니다.

Insertion Point

binarySearch메소드에서 '-1'이 아닌 값이 반환되는 경우는 배열에서 검색하려는 값이 존재하지 않을 경우에 발생합니다.
이러한 경우 '-1' 대신 반환되는 값은 신제로 해당 요소가 배열에 삽입되어야 하는 위치를 나타내는 것으로 이 위치를 "삽입 포인트(Insertion Point)라고 합니다."

Insertion Point 사용 예제

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

public static void insertionPoint() {
    int[] intArr = new int[]{1, 2, 3, 4, 5, 6, 8, 9};
    int target = 7;
    // 배열에서 1부터 9까지 있지만 7은 비어 있기 때문에 7을 채워보자

    int insertionPoint = Arrays.binarySearch(intArr, target);
    // 1. 7을 key 값으로 전달하여 찾아 본다. 없기 때문에 insertionPoint를 반환한다.
    System.out.println(insertionPoint);
    // 출력 : -7이다.

    if (insertionPoint < 0) {
        // 만약 insertionPoint 값이 음수라면 진행
        int IP = -insertionPoint - 1;
        // 먼저 배열에 삽입할 index 값으로 변환한다.
        // 이 과정에서 배열의 길이보다 -1을 하고 음수에서 양수로 변환
        System.out.println(IP);
        // 출력 : 6

        // 동적으로 Array를 조작해야 하기 때문에 ArrayList를 만든다.
        List<Integer> tmpArrList = new ArrayList<>(Arrays.asList(Arrays.stream(intArr).boxed().toArray(Integer[]::new)));
        // 위에서 만든 tmpArrList에 intArr2의 모든 값을 추가한다.
        // int[] => Integer[] => List<Integer> 형태로 전환된다.

        tmpArrList.add(IP, target);
        // IP index에 target 값이 동적으로 중간에 추가된다.

        intArr = tmpArrList.stream().mapToInt(Integer::intValue).toArray();
        // 위의 과정을 모두 거치고 난 List를 다시 int[] 원시 타입의 배열로 전환하여 할당
    }
    System.out.println(Arrays.toString(intArr));
    // 출력 : [1, 2, 3, 4, 5, 6, 7, 8, 9]
}

copyOf(복사)

public static <T> T[] copyOf(T[] original, int newLength)
// 복사할 배열을 첫 번째 인자로 전달
// 복사된 새로운 배열의 길이 length를 전달, 이 값은 0이상 이어야 한다.
// 만약 0 이하의 값을 전달하면 Exception 발생

copyOf메소드는 배열을 새로운 배열에 값을 복사하는 메소드입니다.
coptOf메소드는 original 배열의 처음부터 newLength까지의 요소를 복사하여 새로운 배열을 생성합니다.
만약, newLength가 original배열의 길이보다 작을 경우, 새로운 배열은 newLength길이로 자릅니다. 반대로, newLength가 original배열의 길이보다 클 경우, 추가 요소는 null로 채워집니다.

copyOf메소드는 original 배열과 동일한 유형의 배열을 반환합니다. 반환된 배열은 원본 배열과 요소 값은 동일하지만 다른 객체입니다. 이를 통해 원본 배열과 복사된 배열이 서로 독립적으로 사용될 수 있습니다.

public static void arrayCopy() {
    int[] origin = new int[]{1, 5, 2, 4, 6, 3};
    int[] copyArr1 = Arrays.copyOf(origin,5);
    int[] copyArr2 = Arrays.copyOf(origin,2);
    int[] copyArr3 = Arrays.copyOf(origin,8);

    System.out.println(Arrays.toString(copyArr1));
    // 출력 : [1, 5, 2, 4, 6, 3]
    System.out.println(Arrays.toString(copyArr2));
    // 출력 : [1, 5]
    System.out.println(Arrays.toString(copyArr3));
    // 출력 : [1, 5, 2, 4, 6, 3, 0, 0]
}

copyOf메소드는 얕은 복사(shallow copy)를 수행합니다.
즉, 복사된 배열은 원본 배열의 요소들을 참조합니다. 따라서 원 배열의 요소가 객체일 경우, 복사된 배열과 원본 배열은 같은 객체를 참조하게 됩니다.


equals(비교)

public static boolean equals(type[] a, type[] b)

equals메소드는 배열 간의 동등성(equality)을 비교하는 메소드입니다. 이 메소드는 두 배열이 같은 길이를 가지고 있고, 동일한 순서로 동일한 요소를 가지고 있는지 확인합니다.

equals(비교) 동작 방식

'a', 'b' : 비교할 두 배열입니다. 이 배열들은 동일한 유형의 요소를 가지고 있어야 합니다.

  1. 'a'와 'b'의 길이를 비교하여 길이가 다르면 false를 반환
  2. 'a'와 'b'의 각 요소를 동일한 순서로 비교하고, 하나라도 다른 요소가 있다면 false를 반환
  3. 모든 요소가 동일하다면 true를 반환

equlas 예제

public static void arrayEqu() {
    int[] intArr1 = new int[]{2, 6, 4, 3, 1, 5};
    int[] intArr2 = new int[]{2, 6, 4, 3, 1, 5};
    int[] intArr3 = new int[]{2, 6, 4, 3, 1};
    int[] intArr4 = new int[]{2, 6, 4, 3, 5, 1};
    System.out.println(Arrays.equals(intArr1, intArr2));
    // 출력 : true
    System.out.println(Arrays.equals(intArr1, intArr3));
    // 출력 : false
    System.out.println(Arrays.equals(intArr1, intArr4));
    // 출력 : false
}

toString(문자열 변환)

public static String toString(type[] arr)

toString메소드는 java에서 배열의 내용을 문자열로 변환하는데 사용되는 메소드입니다. 이 메소드는 배열의 각 요소를 문자열로 변환하고, 각 요소를 쉼표로 구분하여 한 줄의 문자열로 반환합니다.

toString 동작 방식

  1. 배열의 각 요소를 문자열로 변환합니다. 이는 요소의 'toString()'메소드를 호출하여 기본적인 문자열 표현을 얻는 것을 의미합니다.
  2. 각 요소를 쉼표로 구분하여 한 줄의 문자열로 결합합니다.
  3. 최종 문자열을 반환합니다.

toString 예제

public static void arraysToString() {
    int[] intArr = new int[]{1, 2, 3, 4, 5};
    char[] charArr = new char[]{'a', 'b', 'c', 'd'};

    System.out.println(Arrays.toString(intArr));
    // 출력 : [1, 2, 3, 4, 5]
    System.out.println(Arrays.toString(charArr));
    // 출력 : [a, b, c, d]
}

asList(리스트 변환)

public static <T> List<T> asList(T... arr)
// arr은 List로 변환할 배열입니다.

asList메소드는 배열을 List로 변환하는 메소드입니다.
또한 List는 원시 타입으로 만들수 없기 때문에 Wrapper(래퍼)클래스로 바꾸어서 저장하는 작업이 필요할 수도 있습니다.

asList 동작 방식

  1. 주어진 배열을 가변 인자(varargs)로 받습니다.
  2. 배열의 요소를 포함하는 고정 크기의 List를 생성합니다.
  3. 생성된 List는 원본 배열의 참조를 유지하므로, 원본 배열의 요소 변경이 List에 반영됩니다.

asList 예제

static void arraysAsList() {
    String[] strArr = {"a", "b", "c"};
    Integer[] integerArr = {1, 2, 3, 4, 5};
    int[] intArr = {5, 4, 3, 2, 1};


    List<String> strList = Arrays.asList(strArr);
    List<Integer> integerList = Arrays.asList(integerArr);


    List<Integer> boxedToArrList = Arrays.asList(Arrays.stream(intArr).boxed().toArray(Integer[]::new));
    List<Integer> boxedCollectList = Arrays.stream(intArr).boxed().collect(Collectors.toList());
    // stream.boxed를 통해 int를 Integer로 박싱 하는 작업

    System.out.println(strList);
    // 출력 : [a, b, c]
    System.out.println(integerList);
    // 출력 : [1, 2, 3, 4, 5]
    System.out.println(boxedToArrList);
    // 출력 : [5, 4, 3, 2, 1]
    System.out.println(boxedCollectList);
    // 출력 : [5, 4, 3, 2, 1]
}
profile
그럭저럭 어렵지 않게 Smile!

0개의 댓글