ArrayList
ArrayList
란 자료구조의 한 종류로서 Java에서 가장 많이 사용되는 데이터 스트럭쳐입니다.
알고리즘에서 많이 활용되며, 실무에서 데이터를 다룰 때 입출력하는 부분에서 매우 많은 비중을 차지하고 있습니다.
하지만 이런 ArrayList를 다룰 때 지원하는 메소드를 숙지하고 있지 못하면 ArrayList의 성능을 제대로 활용할 수 없겠죠? 😱
그래서 심화적인 부분은 아니지만 메소드를 활용할 수 있도록 익혀놓는다면 필요할 때 떠올려 관련 자료를 찾아보며 해결할 수 있는 능력이 생길테고, 나중엔 본인 것으로 자연스럽게 남아 언젠간 ArrayList에 통달할 수 있겠습니다!
작성자인 저 또한 공부하면서 정리하는 부분이기 때문에 틀린 정보가 있을 수 있으니 혹시 틀린점이 있다면 피드백 부탁드립니다. :)
참고자료 : ArrayList (Java 8)
ArrayList 생성
1 | import java.util.ArrayList; |
ArrayList를 사용하려면 객체를 생성해야합니다. import는 java.util.ArrayList
로 하면 되겠습니다.
타입은 Integer로 선언하였습니다.
add(E e)
ArrayList 객체가 생성되어 있다면 값이 있어야겠죠? 만약 값이 없는 채로 출력되면 텅텅 빈 엘리먼트만 나올 것입니다.
1 | numbers.add(10); |
생성한 객체에 add
로 Integer 타입을 넣어주면 numbers에는 총 5개의 엘리먼트가 들어가게 됩니다.
그리고 출력을 하면..
[10, 20, 30, 40, 50]
위 결과가 나오겠죠?
여기서 알 수 있는건 바로 .add() 한 순서대로
엘리먼트가 들어간 것을 알 수 있습니다.
그러면 저 사이에 값을 넣는건 불가능 할까요? 😭
NOPE!! 다행히도 index
를 기준으로 add가 가능합니다. 🎉
add(int index, E element)
기존 총 5개의 엘리먼트 중 2번째에 15라는 값을 넣어보겠습니다.
1 | numbers.add(1, 15); |
index는 0부터 시작하고 1에 15라는 엘리먼트를 넣겠다는 의미입니다.
그렇다면 결과는..
[10, 15, 20, 30, 40, 50]
위와 같이 나오게 됩니다.
이제 각 하나의 엘리먼트 들을 넣는 방법은 알았습니다.
그렇다면 하나의 ArrayList에 또 다른 ArrayList의 엘리먼트들을 넣고싶을 땐 어떻게 해야할까요?
바로 addAll()
을 이용하는 방법입니다.
addAll(Collection<? extends E> c)
여기서 Collection은 현재 사용중인 ArrayList와 같은 자료구조를 뜻합니다.
이 메소드는 위에 설명한 것과 같이 하나의 자료구조에 또 다른 자료구조의 엘리먼트를 넣는데에 사용됩니다.
1 | ArrayList<Integer> newNumbers = new ArrayList<>(); |
기존 numbers에 새롭게 만든 ArrayList를 addAll() 합니다.
[10, 15, 20, 30, 40, 50, 60, 70, 80, 90, 100]
그럼 위 엘리먼트들을 얻을 수 있을 것입니다.
여기서 유추할 수 있는 것은 add()도 마찬가지고 index
를 기준으로 addAll()이 가능합니다.
addAll(int index, Collection<? extends E> c)
index를 명시하여 해당 공간에 addAll()이 가능합니다.
1 | ArrayList<Integer> newNumbers = new ArrayList<>(); |
add()와 다른 점은 메소드 이름의 차이 뿐입니다.
[10, 15, 60, 70, 80, 90, 100, 20, 30, 40, 50]
2번 째 index에 addAll() 된 것을 볼 수 있습니다.
그렇다면 넣은 엘리먼트들을 싹다 빼는 방법에 대해 알아보겠습니다.
clear()
이 메소드는 이전에 무슨 작업을 하건 말건 상관없이 무조건 깔.끔. 하게 비워
줍니다.
1 | ArrayList<Integer> numbers = new ArrayList<>(); |
엘리먼트가 넣어진 numbers에 clear()가 선언된 모습 (곧 게워낼 예정..)
[]
그 전까지 부자였던 numbers가 빈털털이가 된 모습… 💀
clone()
clear()가 시원하게 게워냈다면 이 메소드는 있던걸 풍.만. 하게 복제
합니다.
1 | ArrayList<Integer> numbers = new ArrayList<>(); |
clone() 하기 위해 새롭게 만든 ArrayList에 기존 ArrayList를 clone() 합니다.
[10, 15, 20, 30, 40, 50]
numbers에 있던 엘리먼트가 똑같이 newNumbers로 복제된 모습입니다.
contains(Object o)
contains()
는 어떤 구체적인 객체가 있는지 확인하는 메소드입니다.
1 | ArrayList<Integer> newNumbers = new ArrayList<>(); |
numbers에 100이라는 엘리먼트가 포함되어 있다면 문장을 출력하는 예제입니다.
당연히 객체는 존재할 것이고 100도 존재하니 아래와 같은 값이 나오겠죠?
100을 가지고 있습니다.
만약 contains에 없는 객체를 넣었다면 else문을 탄 값이 출력될 것입니다.
forEach(Consumer<? super E> action)
forEach
는 for-loop를 좀 더 효율적으로 사용하는 방법으로 Java8에서는 람다식으로 표현이 가능합니다.
1 | numbers.forEach(number -> System.out.println(number)); |
number 변수를 선언하여 람다식으로 출력하였습니다.
10 15 20 30 40 50 60 70 80 90 100
정말 간단하게 for-loop를 구현할 수 있습니다.
get(int index)
get()
은 ArrayList 내부의 엘리먼트를 가져올 수 있습니다.
1 | if (!numbers.isEmpty()) { |
numbers가 비어있지 않다면 0번 인덱스를 출력하는 예제입니다.
여기서 isEmpty()는 아직 몰라도 되는 부분입니다. 추후에 나오게 됩니다. 😀
첫 번째 엘리먼트 값 : 10
ArrayList의 0번 째에 위치해있는 엘리먼트가 출력됩니다.
indexOf(Object o)
indexOf()
는 ArrayList 안에있는 엘리먼트가 어디에 있는지 찾기 위해 사용하는 메소드 입니다.
1 | ArrayList<Integer> numbers = new ArrayList<>(); |
총 11개의 엘리먼트 중, 30에 대한 위치를 찾기 위한 예제입니다.
3
30은 4번 째에 위치하고 있기 때문에 3이 출력됩니다.
isEmpty()
ArrayList에 엘리먼트들이 있는지 확인하는 메소드입니다. 값은 boolean
으로 출력됩니다.
1 | ArrayList<Integer> numbers = new ArrayList<>(); |
numbers가 비어있는지 확인합니다.
false
false가 뜬 이유는 numbers에 엘리먼트가 있기 때문입니다. 물론 엘리먼트가 없다면 true로 뜨겠죠?
여기서 응용력이 빠르신 분들은 벌써 ArrayList에서는 isEmpty()로 Null
체크가 가능하다는 것을 눈치 채셨을 것입니다.
여기서 더 나아가 Null체크까지 해보신다면 좋을 것 같습니다. 😀
iterator()
iterator()
는 반복을 통해 순회하면서 탐색할 때 사용합니다.
보통 객체지향시 주로 사용하게 되는 기법이며 iterator()를 사용하기 위해선 객체
를 먼저 생성해주어야 합니다.
기본적으로 ArrayList는 순환 중 CRUD가 불가능 하지만 Iterator를 통해서 유일하게 안전한 방법으로 순환 중 다룰 수 있습니다.
Iterator 인터페이스는 아래와 같은 메소드를 지원합니다.
- hasNext() : 다음 엘리먼트가 있는지 확인합니다. 즉, 현재 위치에서 다음 위치로 이동할 수 있는지 판단합니다.
- next() : 다음 엘리먼트를 가져오는 역할을 합니다.
- remove() : next()로 가져온 엘리먼트를 삭제합니다.
1 | Iterator<Integer> iterator = numbers.iterator(); |
while-loop를 하면서 ArrayList에 있는 엘리먼트들을 next 변수에 담고, 만약 10이 포함되어 있다면 remove() 한 후 다시 iterator를 선언하고 출력하는 예제입니다.
10 15 20 30 40 50 60 70 80 90 100 / 15 20 30 40 50 60 70 80 90 100
10이라는 엘리먼트가 존재하니 remove()를 통해 삭제를 했고 삭제된 ArrayList를 다시 담아 출력하였더니 10이 제외된 엘리먼트가 출력되었습니다.
lastIndexOf(Object o)
앞전에 우리는 indexOf(Object o)를 활용하여 엘리먼트가 어디에 위치하고 있는지 알아내 보았습니다.lastIndexOf()
는 엘리먼트가 존재한다면 해당 엘리먼트 중 가장 뒤에있는 index를 출력하고,
만약 엘리먼트가 없다면 -1
을 리턴합니다.
1 | ArrayList<Integer> numbers = new ArrayList<>(); |
80, 50000 두 가지의 엘리먼트를 찾아보겠습니다.
8 / -1
위와 같은 결과가 나오는 이유는 80은 index가 6과 8에 위치하고 있으므로 마지막 index 값인 8이 출력된 것이고
50000은 존재하지 않기 때문에 -1이 출력된 것입니다.
listIterator()
기존 iterator()는 순방향을 통해서만 순회가 가능했지만 listIterator()
는 양방향으로 이동이 가능합니다.
1 | ListIterator<Integer> listIterator = numbers.listIterator(); |
iterator()와 크게 차이는 없습니다.
10 15 20 30 40 50 60 70 80 90 100 / 100 90 80 70 60 50 40 30 20 15 10
역순으로 반복된 것을 확인할 수 있습니다.
listIterator(int index)
listIterator()가 첫 index부터 끝까지 순환했다면 listIterator(int index)는 선언한 index 이후로 순환하게 됩니다.
1 | ListIterator<Integer> listIterator = numbers.listIterator(5); |
ListIterator 선언시 index를 포함하여 선언해주면 됩니다.
50 60 70 80 90 100 / 100 90 80 70 60 50
index 5번 부터 순환된 것을 알 수 있습니다.
remove(int index)
remove는 삭제하는 역할을 하는 메소드입니다. index
를 통해서 해당 엘리먼트를 삭제합니다.
1 | ArrayList<Integer> numbers = new ArrayList<>(); |
0번 째 index를 remove합니다.
[15, 20, 30, 40, 50, 60, 70, 80, 90, 100]
첫 번째 엘리먼트가 삭제된 결과입니다.
remove(Object o)
index 뿐만 아니라 엘리먼트(객체)
자체를 삭제할 수도 있습니다.
1 | numbers.remove(Integer.valueOf(100)); |
100인 엘리먼트를 삭제하고 다시 ArrayList를 호출하였습니다.
[10, 15, 20, 30, 40, 50, 60, 70, 80, 90]
100이 삭제된 결과를 볼 수 있습니다.
removeAll(Collection<?> c)
ArrayList에서 또 다른 ArrayList에 있는 엘리먼트를 전부
제거하는 메소드입니다.
1 | ArrayList<Integer> numbers = new ArrayList<>(); |
기존 ArrayList를 조금 변형하여 동일한 엘리먼트를 add() 후 removeAll()을 하였습니다.
[10, 20, 50]
동일한 30, 40 엘리먼트를 삭제하고 출력되었습니다.
removeIf(Predicate<? super E> filter)
removeIf는 Predicate
를 인자로 받습니다. 이 메소드는 삭제시 필터링
을 하는 작업이 필요할 때 사용합니다.
1 | ArrayList<Integer> numbers = new ArrayList<>(); |
람다식을 사용하여 3으로 나누었을 때 0이 되는 엘리먼트는 삭제를 합니다.
[10, 20, 40, 50]
3으로 나누어지는 30 엘리먼트가 없어진 것을 확인할 수 있습니다.
replaceAll(UnaryOperator operator)
replaceAll()은 두 ArrayList의 엘리먼트 중 같은 엘리먼트
만 담을 때 사용합니다.
1 | ArrayList<Integer> numbers = new ArrayList<>(); |
10, 20 두 엘리먼트만 같고 나머지 세 개의 엘리먼트는 다릅니다.
[10, 20]
위 결과처럼 같은 엘리먼트만 담게 되고 그 결과가 출력될 것입니다.
set(int index, E element)
ArrayList에 들어있는 엘리먼트를 교체
하고 싶을 떄 사용합니다.
1 | ArrayList<Integer> numbers = new ArrayList<>(); |
0 index를 100으로 교체하는 예제입니다.
[100, 20, 30, 40, 50]
원래 10이었던 값이 100으로 변한 것을 볼 수 있습니다.
size()
size()는 ArrayList의 엘리먼트의 수
를 알고싶을 때 사용합니다.
여기서 주의할 점은 length()는 배열의 전체 크기
를 나타내므로 혼동하면 안됩니다❗
1 | ArrayList<Integer> numbers = new ArrayList<>(); |
ArrayList의 총 엘리먼트
를 돌면서 index의 값들을 뽑아내는 예제입니다.
10 20 30 40 50
총 5개의 엘리먼트가 출력될 것입니다.
sort(Comparator<? super E> c)
ArrayList를 sorting 하기 위해서 Collections
의 sort() 메소드를 사용할 수 있습니다.
1 | ArrayList<Integer> numbers = new ArrayList<>(); |
뒤죽박죽 추가된 ArrayList를 sorting하는 예제입니다.
[10, 20, 30, 40, 50]
오름차순
으로 정렬된 것을 확인할 수 있습니다.내림차순
으로 정렬하고 싶다면 reverse()
를 사용하면 됩니다.
subList(int fromIndex, int toIndex)
subList()는 먼저 생성된 ArrayList에서 원하는 엘리먼트를 index로 가져와서 ArrayList를 구성할 때 사용합니다.
1 | ArrayList<Integer> numbers = new ArrayList<>(); |
newNumbers라는 새로운 List에 1~2의 index를 포함하는 엘리먼트를 가지게 하는 예제입니다.
[10, 20, 30, 40, 50] / [20, 30]
아닛? 분명 index 1부터 3까지를 생성해달라고 했는데 어째서 2까지만 생성된거지? 라는 의문을 가질 수 있습니다.
이 메소드 파라미터의 int toIndex
는 미만
이라는 특징이 있습니다. 그래서 3을 주면 실질적으로는 2까지의 엘리먼트를 가져오게 됩니다.
toArray()
로직을 작성하다 보면 ArrayList
를 array
로 변환해야 할 때가 있습니다. 그 때 사용하는 메소드입니다.
1 | ArrayList<Integer> numbers = new ArrayList<>(); |
array를 생성하여 numbers에 담긴 엘리먼트를 담고 출력하는 예제입니다.
10 20 30 40 50
배열로 옮겨진 엘리먼트가 출력되었습니다.
asList()
이전엔 ArrayList를 array로 변환했다면, 이번엔 array
를 ArrayList
로 만들 차례입니다.
1 | String[] array = new String[3]; |
생성된 array룰 ArrayList에 Array.asList로 변환시켜주었습니다.
Java 8 문법인 람다식을 사용하여 for-loop를 사용해봤습니다.
오늘은즐거운금요일
옮겨진 엘리먼트가 출력된 것을 볼 수 있습니다.