[Java] 05. 배열과 List, Map의 사용법


Study/Java  2020. 5. 4. 18:17

안녕하세요. 명월입니다.


이 글은 Java에서 사용되는 배열과 List, Map의 사용법에 대한 글입니다.


배열은 예전 C/C++에서 데이터를 데이터 타입의 크기에 따라 순차적으로 나열하는 것을 배열이라고 했습니다. Java에서 런타입 메모리 구조이기 때문에 데이터가 메모리에 순차적으로 나열되는 것이 크게 의미가 없습니다. 어차피 모두 참조식으로 데이터를 가져오기 때문입니다.

그럼에도 있는 이유는 같은 자료형을 변수를 반복적으로 선언하는 것보다 배열로 선언하는 것이 불필요한 변수명을 줄일 수 있고, 연길 리스트에서의 링크 참조 포인터로 검색을 하는 것이 아니기 때문에 아무래도 검색이 훨씬 빠릅니다.


배열을 선언하는 것은 변수의 대괄호로 선언할 수 있습니다.

public class Test {
  // 실행 함수
  public static void main(String[] args) {
    // 배열 길이 3을 선언하면 0, 1, 2의 배열이 선언된다.
    // array[3]은 포함되지 않는다.
    int[] array = new int[3];
    // 데이터를 입력, indexer 방식
    array[0] = 0;
    array[1] = 1;
    array[2] = 2;
    // 0부터 2까지의 배열을 콘솔에 출력한다.
    for (int i = 0; i < 3; i++) {
      // 콘솔 출력
      System.out.println("array[" + i + "] = " + array[i]);
    }
    // 콘솔에 개행 출력
    System.out.println();
    // 배열에 개수를 선언하지 않고 중괄호를 통해서 튜플식으로 데이터를 입력할 수 있다.
    array = new int[] { 9, 8, 7, 6, 5, 4, 3, 2, 1 };
    // array의 개수만큼 콘솔에 출력한다. (array.length - 배열 개수)
    for (int i = 0; i < array.length; i++) {
      // 콘솔 출력
      System.out.println("array[" + i + "] = " + array[i]);
    }
  }
}

위의 대괄호를 하나 사용한 것을 일차원 배열이라고 합니다. 그럼 배열 안에 배열을 사용할 수 없을까?

그것을 다차원 배열이라고 표현하고 대괄호의 열고 닫힘의 개수만큼 차수가 증가합니다.

public class Test {
  // 실행 함수
  public static void main(String[] args) {
    // 다차원 배열을 이용하여 구구단을 만든다.
    int[][] multiplicationTable = new int[9][9];
    // 단 1단부터 9단까지
    for (int i = 1; i <= 9; i++) {
      // 각 단은 1부터 9까지
      for (int j = 1; j <= 9; j++) {
        // 구구단 작성.
        // 배열의 특성상 시작이 0부터 시작하기 때문에 각 단의 -1를 하는 것으로 표현
        multiplicationTable[i - 1][j - 1] = i * j;
        // 테이블 출력
        System.out.print(j + " * " + i + " = " + (i * j) + "\t");
      }
      System.out.println();
    }
    System.out.println();
    // 배열은 0으로 시작하기 때문에 7단은 배열 array[6]에 있음
    System.out.println("7 * 7 = " + multiplicationTable[7 - 1][7 - 1]);
    System.out.println("6 * 8 = " + multiplicationTable[6 - 1][8 - 1]);
    System.out.println("8 * 3 = " + multiplicationTable[8 - 1][3 - 1]);
  }
}

배열의 단점은 선언할 때 개수를 선언하고 그 이상의 값을 넣게 되면 에러가 발생합니다.

public class Test {
  // 실행 함수
  public static void main(String[] args) {
    // 배열을 3개 선언, array[0], array[1], array[2]
    int[] array = new int[3];
    // 그러나 선언하지 않는 array[3]에 데이터를 입력하면 에러가 발생한다.
    array[3] = 100;   
  }
}

이것을 정적 선언이라고 하는데, 우리가 복수의 데이터를 취급할 때 몇개의 데이터를 미리 아는 경우도 있지만 입력의 개수를 모르는 경우도 많습니다.

이를 동적 선언의 개념인데 이것은 배열이 아닌 List로 취급할 수 있습니다.


Java에서는 List 객체가 인터페이스로 구성되어 있고 실제 클래스는 ArrayList와 LinkedList가 있습니다.

ArrayList는 내부적으로 배열 형식으로 구성되어 있고 LinkedList는 연결 리스트의 구조입니다. (자료구조와 알고리즘은 별도의 글로 설명하겠습니다.)

// List를 사용하기 위해서는 import는 해야 한다.
import java.util.List;
import java.util.ArrayList;
import java.util.LinkedList;
public class Test {
  // 실행 함수
  public static void main(String[] args) {
    // 인터페이스에의 제네릭에 사용할 데이터 타입을 선언한다.
    // 원시적 데이터 타입(Primitive Type)은 허용하지 않습니다.
    // 선언부의 제네릭에서 데이터 타입을 지정했으면 할당부의 제네릭에서는 데이터 타입이 생략 가능합니다.
    List<Integer> array = new ArrayList<>();
    List<Integer> linked = new LinkedList<>();
    // List에서는 개수를 지정하지 않으니 몇개를 넣을 수도 뺄수도 있다.
    array.add(10);
    array.add(200);
    array.add(1000);
    array.add(30000);
    // 0번째 값을 제거
    array.remove(0);
    // 개수 만큼 출력
    for (int i = 0; i < array.size(); i++) {
      // 콘솔 출력
      System.out.println("array (" + i + ") = " + array.get(i));
    }
    // 사용법은 ArrayList와 같다. 그러나 처리 속도가 다르다.
    linked.add(200);
    linked.add(300);
    // 개수 만큼 출력
    for (int i = 0; i < linked.size(); i++) {
      // 콘솔 출력
      System.out.println("linked (" + i + ") = " + linked.get(i));
    }
  }
}

배열의 경우는 복수의 개수를 선언하면 값을 0으로 설정할 수는 있어도 특정 배열의 위치를 제거할 수는 없었습니다. 그러나 List의 경우는 입력의 개수를 정할 필요없이 입력이 가능하며 필요하지 않으면 삭제하는 것도 가능합니다.

LinkedList도 ArrayList와 같은 List 인터페이스를 상속 받았기 때문에 기본적은 사용 방법은 같습니다.


리스트는 배열에 비하면 상당히 동적이고 데이터 삽입 삭제가 자유롭습니다. 그러나 무언가의 데이터를 탐색하기 위해서는 배열과 리스트는 크게 다르지 않습니다.

위 예제에서는 한두개의 데이터이기 때문에 어려움이 없어 보입니다만, 데이터가 몇만개가 된다고 하면 탐색도 꽤 중요합니다.


그래서 List 구조에 키로 등록할 수 있는 구조가 Map입니다.

Map 역시 인터페이스에 두개의 클래스로 이루어져 있습니다.

// Map를 사용하기 위해서는 import는 해야 한다.
import java.util.Map;
import java.util.HashMap;
import java.util.TreeMap;
public class Test {
  // 실행 함수
  public static void main(String[] args) {
    // 두 개의 제네릭 타입을 선언한다.
    // 첫번째 제네릭은 키의 타입이고 두번째 제네릭은 데이터 타입이다.
    Map<Integer, String> hash = new HashMap<>();
    Map<Integer, String> tree = new TreeMap<>();
    // 키 10으로 지정된 hello 데이터를 삽입한다.
    hash.put(10, "hello");
    // 키 20으로 지정된 world 데이터를 삽입한다.
    hash.put(20, "world");
    // 키가 20인 데이터를 출력한다.
    System.out.println("hashmap(20) = " + hash.get(20));
    // 키 10으로 지정된 hello 데이터를 삽입한다.
    tree.put(10, "hello");
    // 키 20으로 지정된 world 데이터를 삽입한다.
    tree.put(20, "world");
    // 키가 10인 데이터를 출력한다.
    System.out.println("treemap(10) = " + tree.get(10));
    // List처럼 키로 데이터를 삭제하는 것이 가능하다.
    tree.remove(20);
  }
}

실제 업무에서는 배열보다는 List나 Map을 많이 사용합니다. 보통 데이터베이스에서 데이터를 취득하면 List에 데이터를 넣고 다루는 것을 많이 하고 Map도 키를 통해 데이터를 분류할 때 많이 사용됩니다.

이것이 조금 더 확대된 다면 stream 식으로 발전되어서 좀 더 sort나 데이터 탐색에 빠르고, 유용하게 사용합니다.


이것에 관해서는 더 자세하게 따로 글을 작성하겠습니다.


여기까지 Java에서 사용되는 배열과 List, Map의 사용법에 대한 글이었습니다.


궁금한 점이나 잘못된 점이 있으면 댓글 부탁드립니다.