Programmers/JAVA

[ ArrayList 생성 ], [ ArrayList 메소드 ], [ ArrayList ↔ List 변경 ]

giggs 2023. 1. 14. 10:36

 

 

-- INDEX --

 

1. ArrayList 생성 2. ArrayList 메소드 3. 배열 변경
import java.util.ArrayList; add(); / addAll();
clear();  / clone();
contains(); / forEach(); / get();
toArray();
ArrayList arrayList
= new ArrayList();
indexOf(); / lastIndexOf();
 size(); / isEmpty()
iterator(); / remove();
 removeAll(); -- retainAll();
asList();
ArrayList <T> arrayList
= new ArrayList <>();
set(); / sort(); / toArray(); stream();

 

 

 

 


 

 

 

 

1.ArrayList 생성

  • import java.util.ArrayList;
  • ArrayList<T> arrayList = new ArrayList<>();
  • new ArrayList() : 기본 크기가 10인 배열 생성
  • new ArrayList(기본크기) : 기본 크기를 지정 (배열이 다 차면 기본크기만큼 사이즈가 증가함)
  • new ArrayList<제네릭>() : 배열 값의 타입을 지정

 

 


 

 

2. 메소드

 

 

2-1 : add()

  • ArrayList.add(E e) - 리스트의 마지막에 인자로 전달된 아이템을 추가한다.
  •  ArrayList.add(int index, E e) - 인자로 전달된 인덱스의 위치에 아이템을 추가한다.

 

 


 

2-2 : addAll() 

  • 두 컬렉션을 합친다.
  • ArrayList.addAll(Collection c) 
  • - 인자로 전달되는 Collection 객체의 모든 아이템을 리스트에 추가한다.
  • ArrayList.addAll(int index, Collection c) 
  • - 리스트의 몇 번째 인덱스부터 아이템을 추가할지 지정가능하다.
  • 인자로 인덱스가 전달되는데, 이 인덱스부터 아이템이 추가된다.

 

 


 

2-3 : clear()

  • 내부의 배열을 모두 null로 초기화하고 size를 0으로 설정한다.
  • 이 메소드는 이전에 무슨 작업을 하건 말건 상관없이 무조건 리스트를 비워줍니다.

 

 


 

2-3 : clone()

  • ArrayList<Integer> numbers = new ArrayList<>();
  • ArrayList<Integer> newNumbers = (ArrayList<Integer>) numbers.clone();
  • 인자는 없고, ArrayList의 복사본을 리턴한다.
  • 리스트의 아이템들을 깊은 복사를 하지 않고 얕은 복사(shallow copy)로 새로운 ArrayList에 set

 

 


 

2-4 : contains()

  • 리스트 안에 어떤 객체가 있는지 확인하는 데 사용하는 메소드
  • contains(Object o) - 객체를 인자로 전달받는다.
  • 리스트에 그 객체가 존재하면 true / 없으면 false를 return 한다.
  • boolean을 리턴하기 때문에, if와 함께 사용할 수 있다.

 

containsAll()

  • argument로 제공한 컬렉션의 모든 값이 포함되어 있는지 여부를 true / false로 반환한다.

 

 


 

2-5 : forEach()

  • forEach()는 리스트를 순회(iterate)하는데 사용되는 메소드.
  • forEach(Consumer<? super E> action) - Consumer 객체를 인자로 받는다.
  •  forEach는 리스트의 모든 아이템에 대해서 Consumer.accept가 수행되도록 한다.
  • 또한, 인자는 람다로 표현할 수 있어 코드를 더욱 간단하게 만든다.

 

String[] fruitsArray = {"apple", "banana", "kiwi", "mango", "blackberry"};
ArrayList<String>  fruits = new ArrayList<>(Arrays.asList(fruitsArray));

Consumer<String> lambda= item -> System.out.println("item : " + item);
fruits.forEach(lambda);

System.out.println("");
fruits.forEach(item -> System.out.println("item : " + item));


//출력 결과
item : apple
item : banana
item : kiwi
item : mango
item : blackberry

item : apple
item : banana
item : kiwi
item : mango
item : blackberry

 

 


 

2-6 : get()

  • ArrayList 내부의 엘리먼트를 가져올 수 있다.
  • get(int index)은 인자로 인덱스를 받는다. 이 인덱스 위치에 있는 객체를 return 한다.
  • 리스트 크기보다 큰 인덱스를 인자로 전달받으면 IndexOutOfBoundsException 발생한다.

 

 


 

2-7 : indexOf()

  •  ArrayList 안에 있는 엘리먼트가 어디에 있는지 찾기 위해 사용하는 메소드
  • 리스트의 앞쪽부터 인자와 동일한 객체가 있는지 찾으며, 존재한다면 그 인덱스를 return 한다.
  • 리스트에 동일한 객체가 2개 이상 존재할 때, 가장 앞에 위치한 객체의 인덱스를 return 한다.
  • 존재하지 않는다면 -1을 return 한다.
  • indexOf(Object value, int startIndex)
  • - 지정된 인덱스부터 마지막 요소까지 탐색. - value가 있으면 전체 ArrayList에서 맨 처음 발견되는 값의 0부터 시작하는 인덱스 return 한다.( 지정 범위 내에서의 index가 아닌 전체 ArrayList에서의 해당 index ) value 없으면 -1 return 한다.
  • IndexOf(Object value, int startIndex, int count)
  • - startIndex에서 시작하여 count개의 요소를 포함하는 ArrayList의 요소 범위에 value가 있으면 처음으로 검색한 개체의 인덱스(0부터 시작)이고, 그렇지 않으면 -1입니다

 


 

2-8 : lastIndexOf()

  • 리스트의 뒤쪽부터 인자와 동일한 객체가 있는지 찾으며, 존재한다면 그 인덱스를 return 한다.
  • 리스트에 동일한 객체가 2개 이상 존재할 때, 가장 뒤쪽에 위치한 객체의 인덱스를 return 한다.
  • 존재하지 않는다면 -1을 return 한다.
  • lastIndexOf(Object value, int endIndex)
  • - 역방향 첫 번째 요소부터 endIndex까지 탐색 - value가 있으면 전체 ArrayList에서 맨 처음 발견되는 값의 0부터 시작하는 인덱스 return 한다. value 없으면 -1 return 한다.
  • lastIndexOf(Object value, int endIndex, int count)
  • - 역방향 첫 번째 요소부터에서 시작하여 endIndex까지 count개의 요소를 포함하는 value가 있으면 처음으로 검색한 개체의 인덱스(0부터 시작)이고, 그렇지 않으면 -1 return 한다.

 

 


 

2-9 : size()

  • ArrayList의 엘리먼트의 수를 알고 싶을 때 사용
  • size가 0이라면 리스트가 비어있다고 확인할 수 있다. ( = Null 체크 가능 )
  • 여기서 주의할 점은 length()는 배열의 전체 크기를 나타내므로 혼동하지 않도록 주의

 

 


 

2-10 : isEmpty()

  • ArrayList에 엘리먼트들이 있는지 확인하는 메소드
  • 리스트에 저장된 요소가 하나도 없을 때 true를 return
  • 따라서, 리스트가 비어있는지 확인할 수 있다.
  • isEmpty()로 Null체크가 가능

 

+@ 객체가 비어있는지 null인지 체크 주의

  • arrayList.isEmpty() 또는 ArrayList.size() 메소드만으로 리스트가 비어있는지 확인할 수 있지만,
  • ArrayList 객체가 null일 때 이 메소드를 호출하면 NullPointerException이 발생
  • 따라서, 아래와 같이 먼저 null check를 하고 그다음에 isEmpty()로 리스트가 비어있는지 확인해야 합니다.

 

if (list == null || list.isEmpty()) {
    // list is null or empty
}

 

 


 

2-11 : iterator()

  • 반복을 통해 순회하면서 탐색할 때 사용
  • 자바의 컬렉션 프레임워크에서 컬렉션에 저장되어 있는 요소들을 읽어오는 방법을 표준화하였는데 그중 하나가 Iterator
  • 보통 객체 지향 시 주로 사용하게 되는 기법이며 iterator()를 사용하기 위해선 객체를 먼저 생성해주어야 함
    기본적으로 ArrayList는 순환 중 CRUD가 불가능 하지만 Iterator를 통해서 유일하게 안전한 방법으로 순환 중 다룰 수 있다.

 


+@ Iterator 인터페이스는 아래와 같은 메소드를 지원

  • hasNext() : 다음 엘리먼트가 있는지 확인합니다. 즉, 현재 위치에서 다음 위치로 이동할 수 있는지 판단. 
  • next() : 다음 엘리먼트를 가져오는 역할, 있으면 true, 없으면 false
  • remove() : next()로 가져온 엘리먼트를 삭제

 

Iterator<Integer> itr = list.iterator();

while (itr.hasNext()) {

  list.get(itr.next());

}

 

 


 

2-12 : remove()

  • 삭제하는 역할을 하는 메소드. index를 통해서 해당 엘리먼트를 삭제.
  • ArrayList.remove(int index) -인자로 전달된 인덱스 위치의 아이템을 리스트에서 삭제되고, 그 객체를 리턴
  • ArrayList.remove(Object o) - 인자로 삭제하려는 아이템을 전달하고, 리스트에 그 아이템이 존재하여 삭제되는 경우 true를 리턴
  • index 뿐만 아니라 엘리먼트(객체) 자체를 삭제할 수도 있습니다.

 

 


 

2-13 : removeAll() <-> retainAll()

  • ArrayList.removeAll(Collection<?> c)은 인자로 Collection을 받는다.
  • 이 Collection이 포함하고 있는 객체를 해당 ArrayList에서 삭제

 

 

//아래 코드는 movies에서 marvel에 해당하는 항목을 모두 삭제하는 예제
ArrayList<String>  marvel = new ArrayList<>();
marvel.add("Iron man");
marvel.add("Hulk");
marvel.add("Captain america");
System.out.println("marvel: " + marvel.toString());

ArrayList<String>  movies = new ArrayList<>();
movies.add("Untouchable");
movies.add("Spiderman");
movies.add("Captain america");
movies.add("Hulk");
System.out.println("movies: " + movies.toString());

movies.removeAll(marvel);
System.out.println("movies - removeAll(marvel): " + movies.toString());


//출력결과
marvel: [Iron man, Hulk, Captain america]
movies: [Untouchable, Spiderman, Captain america, Hulk]
movies - removeAll(marvel): [Untouchable, Spiderman]

 

retainAll() 

  • argument로 제공한 컬렉션 내에 들어있는 값을 제외하고 모두 지워줌

 

 


 

3-14 : set()

  • ArrayList에 들어있는 엘리먼트를 교체하고 싶을 때 사용
  • arrayList.set(int index, E element)
  • 파라미터로 전달한 index 위치의 값을, 2번째 파라미터(element)로 변경해 줌
  • 변경되기 전 값을 return

 

 


 

3-15 : sort()

  • ArrayList를 sorting 하기 위해서 Collections의 sort() 메소드를 사용할 수 있습니다.
  • ArrayList를 sorting 하기 위해서 List의 sort() 메소드를 사용할 수 있습니다.(Java 8 이후)

 

 

3-15-1 : Collections.sort()

 

#1. Collections.sort(list);

  • ArrayList를 오름차순으로 정렬

 

#2. Collections.sort(list, Collections.reverseOrder());

  • Collections.sort()의 2번째 파라미터로 내림차순 정렬을 나타내는 Comparator를 전달해서, ArrayList를 내림차순으로 정렬

 

#3. Collections.sort(list, String.CASE_INSENSITIVE_ORDER);

  • String.CASE_INSENSITIVE_ORDER 를 전달하면, 대소문자 구분 없이 오름차순으로 정렬됩니다.
  • 여기서 'a'와 'A'는 같은 순위로 취급되므로, 원래의 순서를 유지합니다.

 

#4. Collections.sort(list, Collections.reverseOrder(String.CASE_INSENSITIVE_ORDER));

  • 대소문자 구분 없이, 내림차순으로 정렬합니다.

 

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
 
public class SortArrayList {
    public static void main(String[] args) {
 
        // ArrayList 준비
        ArrayList<String> list = new ArrayList<>(Arrays.asList("C", "A", "B", "a"));
        System.out.println("원본 : " + list); // [C, A, B, a]
 
        // 오름차순으로 정렬
        Collections.sort(list);
        System.out.println("오름차순 : " + list); // [A, B, C, a]
 
        // 내림차순으로 정렬
        Collections.sort(list, Collections.reverseOrder());
        System.out.println("내림차순 : " + list); // [a, C, B, A]
 
        // 대소문자 구분없이 오름차순
        Collections.sort(list, String.CASE_INSENSITIVE_ORDER);
        System.out.println("대소문자 구분없이 오름차순 : " + list); // [a, A, B, C]
 
        // 대소문자 구분없이 내림차순
        Collections.sort(list, Collections.reverseOrder(String.CASE_INSENSITIVE_ORDER));
        System.out.println("대소문자 구분없이 내림차순 : " + list); // [C, B, a, A]
    }
}

 

 


 

 

3-15-2 : List.sort() - Java 8 이후

  • default void sort(Comparator<? super E> c)
  • ava 8 이후부터는 List에서는 sort() 메소드를 호출하여 정렬할 수 있다.
  • Collections 객체를 사용하는 대신 List객체의 sort() 메서드를 사용하여 정렬
  • sort()의 파라미터로 Comparator를 넘겨주는데, 앞의 예제와 달리
  • Comparator 객체에서 Comparator를 가져와서 넘겨주었다.

 

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
 
public class SortArrayList {
    public static void main(String[] args) {
 
        // ArrayList 준비
        ArrayList<String> list = new ArrayList<>(Arrays.asList("C", "A", "B", "a"));
        System.out.println("원본 : " + list);  // [C, A, B, a]
 
        // 오름차순으로 정렬
        list.sort(Comparator.naturalOrder());
        System.out.println("오름차순 : " + list);  // [A, B, C, a]
 
        // 내림차순으로 정렬
        list.sort(Comparator.reverseOrder());
        System.out.println("내림차순 : " + list); // [a, C, B, A]
        
        // 대소문자 구분없이 오름차순 정렬
        list.sort(String.CASE_INSENSITIVE_ORDER);
        System.out.println("대소문자 구분없이 오름차순 : " + list); // [a, A, B, C]
        
        // 대소문자 구분없이 내림차순 정렬
        list.sort(Collections.reverseOrder(String.CASE_INSENSITIVE_ORDER));
        System.out.println("대소문자 구분없이 내림차순 : " + list); // [C, B, a, A]
    }
}

 

 


 

 

4. ArrayList ↔ List 변경

 

 

4-1 : ArrayList에서 List로 변경

 

 

4-1-1 : toArray()

  • ArrayList를 array로 변환해야 할 때 사용하는 메소드이다.
  • ArrayList.toArray() Method의 경우, Object array를 리턴한다.
  • 이럴 경우, 적절히 타입 캐스팅을 해서 사용을 해야 하는 번거로움이 있다.
  • Integer[] array = numbers.toArray(new Integer[numbers.size()]);
  • 위와 같이, 리턴될 array의 타입을 지정해 준다면 타입 캐스팅을 할 필요가 없다.
  • 정리하자면, ArrayList에 여러 가지 class의 object가 있는 경우는, ArrayList.toArray()를 사용하는 것이 편하고,
  • 동일한 class의 object가 있는 경우는 ArrayList.toArray(T[] t)를 사용하시는 것이 편하다.

 


 

 

# arrayList.toArray()

  •  ArrayList의 요소를 새 Object 배열에 복사한다.
  • List 클래스의 인스턴스 메서드인 toArray()는 Object 타입의 배열을 반환한다.
  • 타입 변환이 자동으로 이루어지지 않아서 리턴 배열을 활용하기 번거롭다.

 

 

# arrayList.toArray(T[ ] a)

  •  ArrayList의 요소를 지정된 요소 형식의 새 배열에 복사한다
  • T 타입 배열을 반환한다.
  • T는 값 타입이 될 수 없기 때문에 int, double, float와 같은 타입의 배열은 이 방법으로는 얻을 수 없다.
  • 파라미터 a의 길이는 0으로 지정하면 알아서 list의 길이에 맞게 조정되어 arr에 저장된다.

 

 


 

 

4-1-2 : 배열 length에 따른 size에 따른 차이

  • ArrayList를 배열로 변경할 경우 길이 0의 배열 strs.toArray(new String[0]); 을 넘겨주면
  • ArrayList 길이만큼 배열을 자동으로 생성하고 데이터를 복사하게 됩니다.
  • 메서드 파라미터 a로 넘겨받은 배열의 길이가
  • 1. 해당 ArrayList 객체의 size 보다 작은 경우 (a.length < size) : size만큼 배열을 생성하고 ArrayList의 데이터 복사 후 리턴합니다.
  • 2.a 배열의 길이가 해당 ArrayList 객체의 size 보다 크거나 같은 경우 (1번 체크 이후. a.length >= size) : 배열 a에 ArrayList 데이터를 복사합니다.
  • 3.a 배열의 길이가 > ArrayList 객체 size 경우(a.length > size) : a[size] = null을 할당합니다.
  • 참조타입 배열은 초기화 시 null로 초기화되므로 해당 로직이 필요 없을 수 있지만, 초기화한 배열이 아닌 기존에 값이 들어있는 재사용하고자 전달한 경우엔 필요한 로직입니다.
  • 그래서 ArrayList를 배열로 변경할 경우 길이 0의 배열 strs.toArray(new String[0]); 을 넘겨주면 ArrayList 길이만큼 배열을 자동으로 생성하고 데이터를 복사하게 됩니다.

 

 


 

 

4-2 : List에서  ArrayList 로 변경

 

 

4-2-1 : asList()

  • ArrayList<String> friday = new ArrayList<>(Arrays.asList(array));
  • Arrays.asList()는 리스트를 초기화할 때 자주 사용된다.
  • List를 ArrayList로 변경하는 이유? - 처음에 다 초기화를 해버리는 Array와 달리 List는 빈 리스트를 만든 후 add를 해주는 식으로만 초기화를 해줄 수 있다는 점이 매우 불편하기 때문이다.
  • 그런데, 이 Arrays.asList를 사용할 때에는 주의할 점이 있다.
    위 메서드를 사용할 경우, 이를 할당받는 변수는 원래 만들어진 배열의 인스턴스를 가리킨다.
    이런 이유 때문에 위의 방법으로 초기화된 리스트는 ArrayList의 특성(변경이 자유로운)을 갖지 못한다.
  • Arrays.asList를 이용해 변경이 자유로운 ArrayList를 만들고 싶은 경우에는, ArrayList 클래스의 생성자에 만들어진 List 자료구조를 넣어서 새롭게 만들어진 ArrayList 인스턴스를 참조하도록 해줘야 한다.
  • Arrays의 private 정적 클래스인 ArrayList를 리턴한다.
    java.util.ArrayList 클래스와는 다른 클래스이다.
  • java.util.Arrays.ArrayList 클래스는 set(), get(), contains() 메서드를 가지고 있지만
    원소를 추가하는 메서드는 가지고 있지 않기 때문에 사이즈를 바꿀 수 없다.
  • list에 담겨있는 데이터를 수정했는데 원본 배열의 데이터까지 변경이 됐다.
    List는 내부 구조가 배열로 만들어져 있다.
  • 따라서 asList()를 사용해서 반환되는 List도 배열을 갖게 된다.
  • 이때, asList()를 사용해서 List 객체를 만들 때 새로운 배열 객체를 만드는 것이 아니라,
    원본 배열의 주소값을 가져오게 된다.
    따라서 asList()를 사용해서 내용을 수정하면 원본 배열도 함께 바뀌게 되고
    원본 배열을 수정하면 그 배열로 만들어뒀던 asList()를 이용한 List 내용도 바뀌게 된다.
    이러한 이유 때문에 Arrays.asList()로 만든 List에 새로운 원소를 추가하거나 삭제할 수 없다.
    따라서 Arrays.asList()는 배열의 내용을 수정하려고 할 때 List로 바꿔서 편리하게 사용하기 위함.

 


 

 

4-2-2 : List 타입의 ArrayList가 아닌 Collection 타입의 ArrayList로 변환하기

  • 만약 진짜 ArrayList를 받기 위해서는 다음과 같이 변환하면 된다.
    ArrayList 생성자는 java.util.Arrays.ArrayList의 상위(super) 클래스인 Collection Type
    도 받아들일 수 있다.
  • List<String> list = new ArrayList<String>(Arrays.asList(arr));
  • 이제는 원본 배열과 list 객체에 담겨있는 배열 데이터는 별개의 주소값이라고 보면 된다.

 

package Test;
import java.util.List;
import java.util.ArrayList;
import java.util.Arrays;
 
 
public class TestArrayAsList {
   public static void main(String[] args) {
      String[] strs = {"alpha", "beta", "charlie"};
      System.out.println(Arrays.toString(strs));   // [alpha, beta, charlie]
 
      List<String> lst = new ArrayList<String>(Arrays.asList(strs)); 
      System.out.println(lst);  // [alpha, beta, charlie]
 
      lst.add("ttt");     // 이제는 에러가 나지 않고 데이터를 추가 시킬 수 있다.
 
      // Changes in array or list write thru
      strs[0] += "88";
      lst.set(2, lst.get(2) + "99"); // 2번째 인덱스 원소에 charlie99 넣음
      System.out.println(Arrays.toString(strs)); // [alpha88, beta, charlie]
      System.out.println(lst);  // [alpha, beta, charlie99, ttt]
 
      // Initialize a list using an array
      List<Integer> lstInt = Arrays.asList(22, 44, 11, 33);
      System.out.println(lstInt);  // [22, 44, 11, 33]
   }
}

 

 


 

 

4-2-3 : stream

  • 값 타입 배열을 얻기 위해서는 int 값을 꺼내서 배열로 저장해야 한다. 이때 사용하는 것이 stream이다.
  • list.stream(): Stream<Integer>을 반환한다.
  • mapToInt(Integer::intValue): Integer의 intValue() 메서드를 참조해서 값 타입인 int로 언박싱한다.
  • toArray(): IntStream의 원소를 배열로 변환한다.

 

List<Integer> list = new ArrayList<>();
// ...
int[] arr = list.stream()
	.mapToInt(Integer::intValue)
    	.toArray();

 

 


 

 

 

4-2-4 : stream을 활용하여 primitive 타입 배열 얻기

  • String 타입의 List를 배열로 변환할 때는 toArray()를 사용하면 변환할 수 있다.
  • 하지만 int형과 같은 primitive 타입은 toArray()를 사용할 수 없다.
  • 따라서 int형과 같은 primitive 타입은 아래의 방법을 통해 가능하다.
  • primitive 타입 == 기본형 타입( boolean, byte, short, int, long, float, double, char )

 

public static void main(String args[]) {
    List<Integer> list = new ArrayList<>();
    list.add(1);
    list.add(2);
    list.add(3);
    
    // 방법 1
    int[] arr1 = new int[list.size()]
    for (int i = 0 ; i < list.size() ; i++) {
        arr1[i] = list.get(i).intValue();
    
    // 방법 2
    int[] arr2 = list.stream()
                .mapToInt(i -> i)
                .toArray();
    
    // 방법 3
    int[] arr3 = list.stream()
                .mapToInt(Integer::intValue)
                .toArray();

    // 방법 4
    int[] arr4 = list.stream()
                .filter(i -> i != null)
                .mapToInt(i -> i)
                .toArray();
}

 

 

  • 방법 1은 가장 기본적인 방법으로, 반복문을 통해 각 요소별로 접근하여 intValue 메서드를 사용하여 int형으로 만든 후 배열에 넣는 형식이다.
  • 방법 2와 3은 리스트를 스트림으로 변환 후, map을 이용해서 intStream을 가져오고, 그 후에 toArray()를 통해 배열로 만드는 방법이다.
  • 방법 2와 방법 3의 차이는 map 연산 시 int형으로 변경하는 방법의 차이이다.
  • 방법 2는 자바가 자동으로 각 요소의 Integer 요소를 int형으로 unboxing 해준다. (java 5 이상) 하지만 방법 3은 intValue 메서드를 통해 각 요소를 int형으로 변경해 준다.
  • 방법 4는 방법 2에서 필터를 추가한 방법이다. 필터를 통해 리스트의 null을 걸러내는 방법이다.