저번 글에서 List 인터페이스는 순서를 가지고 중복을 허용한다고 했다.
List인터페이스를 구현한 대표적인 클래스는 ArrayList, Vector, LinkedList가 있다.
각각의 클래스를 활용한 코드를 보면서 학습해보자.
순서에 따라 저장하고, 중복을 허용한다.
1. ArrayList 클래스
2. Vector 클래스
3. LinkedList
구현기능
getMemberId 메서드
를 통해서 인스턴스의 멤버ID를 반환받는다.setMemberId 메서드
를 통해서 인스턴스의 멤버ID를 설정한다.getMemberName 메서드
를 통해서 인스턴스의 멤버이름을 반환받는다.setMemberName 메서드
를 통해서 인스턴스의 멤버이름을 설정한다.toString 메서드
를 오버라이딩해서 출력시 클래스의 정보가 반환될 수 있도록 한다.package collection;
public class Member {
private int memberId;
private String memberName;
public Member(int memberId, String memberName) {
this.memberId = memberId;
this.memberName = memberName;
}
public int getMemberId( ) {
return memberId;
}
public void setMemberId(int memberId) {
this.memberId = memberId;
}
public String getMemberName( ) {
return memberName;
}
public void setMemberName(String memberName) {
this.memberName = memberName;
}
@Override
public String toString() {
return memberName + " 회원님의 아이디는 " + memberId + "입니다." ;
}
}
ArrayList를 활용해서 회원관리 프로그램을 만들어보자.
ArrayList의 메서드를 활용해서 회원을 추가하는 메서드, 삭제하는 메서드, 전체 회원을 출력하는 메서드를 만들었다.
구현 기능
addMember 메서드
로 맨마지막에 member을 추가하거나, 원하는 인덱스 값으로 member을 추가하는 기능 구현getMeber (int memberID) 메서드
로 멤버ID를 가지고 멤버를 반환하는 기능 구현null
을 넣어 구현removeMember(int memberID) 메서드
로 멤버ID를 가진 멤버요소 삭제 showAllMember() 메서드
로 멤버 전체 출력package colletion.arrlist;
import collection.Member;
import java.util.ArrayList;
public class MemberArrayList {
private ArrayList<Member> arrayList;
public MemberArrayList( ) {
arrayList = new ArrayList<Member>();
}
public void addMember(Member member) {
arrayList.add(member);
}
public void addMember(int index,Member member) {
arrayList.add(index,member);
}
public Member getMeber (int memberID) {
for (int i = 0; i < arrayList.size(); i++) {
Member member = arrayList.get(i);
int tempID = member.getMemberId();
if (memberID == tempID) {
return member;
}
}
System.out.println("해당 member없음.");
return null;
}
public boolean removeMember(int memberID) {
for (int i = 0; i < arrayList.size(); i++) {
Member member = arrayList.get(i);
int tempId = member.getMemberId();
if(tempId == memberID) {
arrayList.remove(i);
return true;
}
}
System.out.println(memberID +"가 존재하지 않습니다.");
return false;
}
public void showAllMember() {
System.out.println("meber 전체 출력");
for(Member member : arrayList) {
System.out.println(member);
}
System.out.println();
}
}
ArrayList를 직접 사용하는 것도 유효한 방법이지만, ArrayList를 활용하여
클래스를 작성하면 더 나은 모듈화, 확장성, 테스트 용이성, 코드 가독성을 얻을 수 있습니다.
1. 추상화와 모듈화
회원관리 데이터 저장, 삭제 등 관리에 대한 복잡한 로직을 클래스
내부에 캡슐화할 수 있다.
2. 유연한 확장성
나중에 다른 자료구조로 변경하거나 데이터 저장 방식을 변경하는 등 확장이 쉬워진다.
ex) , ArrayList → LinkedList/Set
3. 기능 확장
회원 관리에 관련된 추가적인 기능을 제공할 수 있다.
중복 회원 검사, 회원 정보 정렬, 특정 조건에 따른 회원 검색 등의 기능을
새로 추가하여 프로그램을 더 유용하게 만들수 있다.
ArrayList만으로는 이런 구현은 불가능하다.
4. 코드 가독성
ArrayList를 직접 사용하는 것보다 클래스명과 메소드명을 통해
코드의 의도를 명확하게 전달할 수 있다.
이를 통해 코드의 가독성이 향상되고 유지보수가 가능해진다.
5. 좋은 설계 원칙 준수
ArrayList를 활용하면 SOLID 원칙과 같은 좋은 소프트웨어 설계 원칙을 준수할 수 있다.
Vector은 두 개 이상의 멀티 스레드 환경에서 동기화를 보장해준다.
동시에 작업이 이루어지는 자원에 대해서 잠금을 수행한다.
👉 Vector의 모든 메서드는 호출될 때마다 잠금과 해제가 일어나므로 속도가 느리다.
Vector로 바꾸지 않고 다음 코드처럼 ArrayList를 생성한다.
Collections.synchronizedList(new ArrayList<String>());
public void SomeMethod() {
List<String> synchronizedList = Collections.synchronizedList(new ArrayList<String>());
synchronizedList.add("MadPlay");
synchronizedList.add("MadPlay");
synchronizedList.add("Kimtaeng");
/*
스레드 간의 동시 접근으로 인해 리스트가 손상될 수 있는 상황을 방지하기 위함입니다.
만약 synchronized 블록을 제거하면 다수의 스레드가 동시에 Iterator를 사용하여
리스트를 수정하거나 반복하는 경우, 경쟁 상태(race condition)와 같은 문제가 발생할 수 있습니다.
이로 인해 예기치 않은 결과, 예를 들어 반복 중간에 다른 스레드가
리스트의 요소를 수정하거나 삭제하는 등의 상황이 발생할 수 있습니다
*/
synchronized(synchronizedList) {
Iterator i = synchronizedList.iterator(); // Must be in synchronized block
while (i.hasNext()) {
foo(i.next());
}
}
}
🤔 배열은 물리적 순서와 논리적 순서가 동일하다.
따라서 중간에 자료를 삽입하거나 삭제하면, 나머지 자료를 이동시켜야 하고,
처음 선언한 배열 크기 이상으로 요소가 추가되는 경우에는 크기가 더 큰 배열을
새로 생성한다는 단점이 있다.
그에 비해서 LinkedList 클래스는 논리적 순서와 물리적 순서가 동일하지 않아서 삭제, 추가시에 더 편리하다.
링크드리스트에 요소 추가하기
링크드리스트에 요소 제거하기
👉 요소를 추가할 떄마다 동적으로 요소의 메모리를 생성하고, 추가하거 나 삭제할 때 편리하다.
하지만, 물리적으로 연결되어 있지 않아서 검색이 느리다는 단점이 있다.
ArrayList : 자료의 변동이 거의 없고, 검색을 자주 해야할 때
LinkedList : 자료의 변동이 많고, 검색이 적을 때
메서드 | 설명 |
---|---|
void addFirst(Object obj) | LinkedList의 맨 앞에 객체(obj)를 추가 |
void addLast(Objec obj) | LinkedList의 맨 뒤에 객체(obj)를 추가 |
boolean add(Object obj) | LinkedList의 마지막에 객체를 추가한다. (성공하면 true) |
void add(int index, Object element) | 지정된 위치(index)에 객체를 저장한다. |
void addAll(Collection c) | 주어진 컬렉션의 모든 객체를 저장한다. (마지막에 추가) |
void addAll(int index, Collection c) | 지정한 위치부터 주어진 컬렉션의 데이터를 저장한다. |
➕ 중간 삽입일 경우: 중간에 삽입할 위치까지의 탐색이 필요하다.
메서드 | 설명 |
---|---|
Obejct removeFirst() | 첫번째 노드를 제거 |
Object removeLast() | 마지막 노드를 제거 |
Object remove() | LinkedList의 첫 번째 요소를 제거 |
Object remove(int index) | 지정된 위치(index)에 있는 객체를 제거한다. |
boolean remove(Object obj) | 지정된 객체를 제거한다. (성공하면 true) |
boolean removeAll(Collection c) | 지정한 컬렉션에 저장된 것과 동일한 노드들을 LinkedList에서 제거한다. |
boolean retainAll(Collection c) | LinkedList에 저장된 객체 중에서 주어진 컬렉션과 공통된 것들만 남기고 제거한다. |
void clear() | LinkedList를 완전히 비운다. |
메서드 | 설명 |
---|---|
int size() | LinkedList에 저장된 객체의 개수를 반환한다. |
boolean isEmpty() | LinkedList가 비어있는지 확인한다. |
boolean contains(Object obj) | 지정된 객체(obj)가 LinkedList에 포함되어 있는지 확인한다. |
boolean containsAll(Collection c) | 지정된 컬렉션의 모든 요소가 포함되었는지 알려줌. |
int indexOf(Object obj) | 지정된 객체(obj)가 저장된 위치를 찾아 반환한다. |
int lastIndexOf(Object obj) | 지정된 객체(obj)가 저장된 위치를 뒤에서 부터 역방향으로 찾아 반환한다. |
메서드 | 설명 |
---|---|
Object get(in index) | 지정된 위치(index)에 저장된 객체를 반환한다. |
List subList(int fromIndex, int toIndex) | fromIndex부터 toIndex사이에 저장된 객체를 List로 반환한다. |
⚠️ 리스트의 크기(size)를 넘기는 인덱스를 할당하게 된다면 배열과 같이 IndexOUtOfBoundsException 예외가 발생한다.
메서드 | 설명 |
---|---|
Object set(int index, Object obj) | 지정한 위치(index)의 객체를 주어진 객체로 바꾼다. |
메서드 | 설명 |
---|---|
Object[] toArray() | LinkedList에 저장된 모든 객체들을 객체배열로 반환한다. |
Object[] toArray(Obejct[] objArr) | LinkedList에 저장된 모든 객체들을 객체배열 objArr에 담아 반환한다. |
➕ List구조로 get(i)를 사용할 수 있지만 Iterator을 추천한다.
✅ 사용방법
Iterator<Member> ir = memberLink.iterator();
Iterator ir = memberLink.iterator();
:✍️ 예시코드
<import java.util.LinkedList;
import java.util.Iterator;
public class LinkedListIteratorExample {
public static void main(String[] args) {
LinkedList<String> linkedList = new LinkedList<>();
linkedList.add("Apple");
linkedList.add("Banana");
linkedList.add("Cherry");
// LinkedList의 Iterator 생성
Iterator<String> iterator = linkedList.iterator();
// hasNext()로 다음 요소가 있는지 확인하고, 있을 때까지 반복
while (iterator.hasNext()) {
// next()로 다음 요소를 가져와서 출력
String element = iterator.next();
System.out.println(element);
}
}
어렵고 복잡하다..ㅎ