Java

[Java] 13. Collection (1) List - ArrayList

hyomee2 2024. 8. 22. 16:41

List

1. List 인터페이스

: 순서가 있는 데이터의 집합으로, 같은 데이터의 중복 저장을 허용한다.

- ArrayList, LinkedList, Vector, Stack


ArrayList

- 크기 변경이 불가능한 배열의 단점을 보완. 기본 배열보다 느릴 수는 있지만 동적 배열이 구현돼 있다.

- ArrayList 인스턴스를 생성하게 되면 내부적으로 10칸짜리 배열을 생성해서 관리한다.

- 크기 변경, 요소 추가/삭제/정렬 기능들을 메소드로 제공한다.

- ArrayList는 스레드 간 동기화가 지원되지 않기 때문에, 다수의 스레드가 동시에 접근하여 데이터를 조작하게 될 경우 데이터 훼손이 일어날 수 있다.

- cf. 모든 컬렉션 프레임워크는 제네릭 클래스로 작성 되어 있다. 

List<String> stringList = new ArrayList<>();
stringList.add("apple");
stringList.add("banana");
stringList.add("orange");
stringList.add("mango");
stringList.add("grape");
// stringList.add(123);

 

1. ArrayList 선언하기

- 다형성을 이용해서 상위 레퍼런스로 ArrayList 객체를 참조할 수 있다.

- List 인터페이스 하위의 다양한 구현체들로 타입 변경이 가능하므로, 상위 타입으로 선언하는 것이 더 유연한 코드이다.

ArrayList alist = new ArrayList();
List list = new ArrayList();  // 레퍼런스 타입은 List로 해두는 것이 유연하다.
Collection clist = new ArrayList();

 

2. 요소 저장하기

- Object 클래스의 하위 타입 인스턴스를 모두 저장 가능

alist.add("apple");
alist.add(123);		//autoBoxing 처리됨(값(int) -> 객체(Integer))
alist.add(45.67);   // autoBoxing 처리됨(값(double) -> 객체(Double))
alist.add(new Date());

/*데이터의 중복 저장 허용(인덱스가 다른 위치에 동일한 값 저장 가능)*/
alist.add("apple");
System.out.println("alist : " + alist);

/* 원하는 위치에 값을 추가할 수 있다. 
값을 중간에 추가하는 경우 인덱스 위치에 덮어쓰는 것이 아니고,
새로운 값이 들어가는 인덱스 위치에 값을 넣고 이후 인덱스는 하나씩 뒤로 밀리게 된다.*/
alist.add(1, "banana");
System.out.println("alist : " + alist);

 

3. 요소의 개수 반환

- 내부 관리 배열의 사이즈는 외부에서 알 필요가 없으므로 제공하지 않는다.

System.out.println("alist.size() : " + alist.size());

 

4. 요소에 접근하기

/* get 메소드에 index를 전달하여 하나의 요소에 접근 가능하다. */
for(int i = 0; i < alist.size(); i++) {
    System.out.println(i + " : " + alist.get(i));
}

 

5. 요소 삭제하기

/* 저장 된 값을 삭제할 때는 remove().
중간 인덱스의 값을 삭제하는 경우 자동으로 인덱스를 하나씩 앞으로 당긴다.*/
alist.remove(2);
System.out.println("alist : " + alist);

 

6. 지정된 위치의 값 수정하기

// 인덱스 1의 값 수정
alist.set(1, true);
System.out.println("alist : " + alist);

 

7. 오름차순으로 정렬하기

/*toString() 메소드가 overriding 되어 있다. 출력해보면 저장 순서를 유지하고 있다.*/
System.out.println("alist : " + alist);

/* 저장 순서대로 유지 된 리스트가 정렬을 하면 문자열 오름차순으로 정렬 된다.
* Collections 는 컬렉션에서 활용되는 기능들을 static 메소드로 구현해 둔 클래스이다. 
* sort() 메소드를 사용하면 list가 오름차순 정렬 처리된 후 정렬 상태가 유지된다.*/
System.out.println("stringList : " + stringList);
Collections.sort(stringList);
System.out.println("stringList : " + stringList);

 

8. 내림차순으로 정렬하기

- 기본적으로 ArrayList에는 역순으로 정렬하는 기능이 제공되지 않기 때문에,

역순으로 정렬하려면 역순 정렬 기능이 있는 LinkedList를 이용해야한다. (ArrayList는 LinkedList로 변경 가능)

- Iterator 반복자 인터페이스를 이용해보면, LinkedList 타입으로 형변환을 해준 후 descendingIterator() 메소드를 사용하면 내림차순으로 정렬된 Iterator 타입의 목록으로 반환해준다.

* Iterator

- 반복자로, 반복문을 이용해서 목록을 하나씩 꺼내는 방식으로 사용한다. 인덱스로 관리되는 컬렉션이 아닌 경우에는 반복문을 사용해서 요소에 하나씩 접근할 수 없기 때문에 인덱스를 사용하지 않고도 반복문을 사용하기 위한 목록을 만들어주는 역할이다.
- hasNext(): 다음 요소를 가지고 있는 경우 true, 없는 경우 false를 반환
- next(): 다음 요소를 반환

stringList = new LinkedList<>(stringList);

Iterator<String> dIter = ((LinkedList<String>) stringList).descendingIterator();

/*역순으로 정렬된 결과를 저장하기 위해선 새로운 ArrayList를 만들어서 저장해두면 된다.*/
list<String> descList = new ArrayList<>();

while(dIter.hasNext()) {
    descList.add(dIter.next());
}

System.out.println("descList: " + descList);

 

* ArrayList 사용 예제

public class BookDTO implements Comparable<BookDTO> {
    private int number;
    private String title;
    private String author;
    private int price;

    public BookDTO(int number, String title, String author, int price) {
        this.number = number;
        this.title = title;
        this.author = author;
        this.price = price;
    }

    public int getNumber() {
        return number;
    }

    public void setNumber(int number) {
        this.number = number;
    }

    public int getPrice() {
        return price;
    }

    public void setPrice(int price) {
        this.price = price;
    }

    public String getAuthor() {
        return author;
    }

    public void setAuthor(String author) {
        this.author = author;
    }

    public String getTitle() {
        return title;
    }

    public void setTitle(String title) {
        this.title = title;
    }

    @Override
    public String toString() {
        return "BookDTO{" +
                "number=" + number +
                ", title='" + title + '\'' +
                ", author='" + author + '\'' +
                ", price=" + price +
                '}';
    }

    /* 제목 내림차순 정렬 기준을 내부 기준으로 설정 */
    @Override
    public int compareTo(BookDTO o) {
        return o.getTitle().compareTo(getTitle()); // 여기에 있는 compareTo는 String 클래스의 compareTo 메서드이다.
        /* String 클래스의 compareTo 메서드는 두 문자열을 사전순으로 비교해서 
        현재 문자열이 비교 대상 문자열보다 사전 순으로 앞에 위치할 경우 음수,
        두 문자열이 같을 경우 0, 사전 순으로 뒤에 위치할 경우 양수를 반환한다.*/
    }
}
/* Compartor 사용 시 제네릭 선언을 함께 해야 compare 메소드의 매개변수 타입이 정의 된다.
* Object 타입인 경우 다운 캐스팅 해서 사용해야 하므로 불편하다. */
public class AscendingPrice implements Comparator<BookDTO> {

    /* sort() 메소드에서 내부적으로 compare 메소드를 호출하여 swap 여부를 결정 */
    @Override
    public int compare(BookDTO o1, BookDTO o2) {

        /* 인스턴스의 가격이 오름차순 정렬 되기 위해서는 앞의 가격이 더 작은 가격이어야 한다.
        * 만약 뒤의 가격이 더 작은 경우 두 인스턴스의 순서를 바꿔야 한다.
        * 그 때 두 값을 바꾸라는 신호로 양수를 반환하면 정렬 시 순서를 바꾸는 조건으로 사용 된다.
        * */

        int result = 0;

        if(o1.getPrice() > o2.getPrice()) {
            result = 1;
        } else if(o1.getPrice() < o2.getPrice()) {
            result = -1;
        }

        return result;
    }
}
public class Application2 {
    public static void main(String[] args) {

        List<BookDTO> bookList = new ArrayList<>();
        bookList.add(new BookDTO(1, "홍길동전", "허균", 50000));
        bookList.add(new BookDTO(2, "목민심서", "정약용", 30000));
        bookList.add(new BookDTO(3, "동의보감", "허준", 40000));
        bookList.add(new BookDTO(4, "삼국사기", "김부식", 46000));
        bookList.add(new BookDTO(5, "삼국유사", "일연", 58000));

        for(BookDTO bookDTO : bookList) {
            System.out.println(bookDTO);
        }

        /* implements Comparable 을 통해 compareTo 메소드(정렬 기준 반환)가 재정의 되어야만 사용 가능 */
        // 우리는 BookDTO에 implements Comparable을 해주지 않았기 때문에 컴파일 에러 발생
        // Collections.sort(bookList); 컴파일 에러

        /* Comparator 인터페이스를 구현한 정렬 기준을 작성한다. */
        System.out.println("가격 오름차순 정렬 ==============");
        // Collections.sort(bookList, new AscendingPrice());
        bookList.sort(new AscendingPrice());
        for(BookDTO bookDTO : bookList) {
            System.out.println(bookDTO);
        }

        /* 정렬 기준을 계속 사용하는 경우 별도의 클래스를 만들어서 사용해도 되지만
        * 한 번만 사용하기 위해서 더 간편하게 익명 클래스(Anonymous class)를 사용할 수도 있다. */
        System.out.println("가격 내림차순 정렬 ==============");
        bookList.sort(new Comparator<BookDTO>() {
            @Override
            public int compare(BookDTO o1, BookDTO o2) {
                return o2.getPrice() - o1.getPrice();
            }
        });
        
        for(BookDTO bookDTO : bookList) {
            System.out.println(bookDTO);
        }

        System.out.println("제목 오름차순 정렬 ===========");
        bookList.sort(new Comparator<BookDTO>() {
            @Override
            public int compare(BookDTO o1, BookDTO o2) {
                /* 문자열 대소비교는 String 클래스에 정의 된 compareTo() 메소드를 활용한다. */
                return o1.getTitle().compareTo(o2.getTitle());
            }
        });
        
        for(BookDTO bookDTO : bookList) {
            System.out.println(bookDTO);
        }

        System.out.println("제목 내림차순 정렬 ===========");
        /* implements Comparable<BookDTO> 수행 후에는 해당 코드가 동작 된다. */
        Collections.sort(bookList);
        for(BookDTO bookDTO : bookList) {
            System.out.println(bookDTO);
        }
    }
}

'Java' 카테고리의 다른 글

[Java] 13. Collection (3) Stack & Queue  (0) 2024.08.23
[Java] 13. Collection (2) List - LinkedList  (0) 2024.08.22
[Java] 13. Collection  (0) 2024.08.22
[Java] 12. 제네릭 프로그래밍  (0) 2024.08.21
[Java] 11. 입출력  (0) 2024.08.21