JAVA 기초 (34) List 인터페이스

코린이서현이·2023년 8월 13일
0

Java

목록 보기
35/46

🧐들어가면서🧐

저번 글에서 List 인터페이스는 순서를 가지고 중복을 허용한다고 했다.
List인터페이스를 구현한 대표적인 클래스는 ArrayList, Vector, LinkedList가 있다.
각각의 클래스를 활용한 코드를 보면서 학습해보자.

📕 List인터페이스

순서에 따라 저장하고, 중복을 허용한다.
1. ArrayList 클래스
2. Vector 클래스
3. LinkedList

📒 각 클래스에서 사용할 Member클래스

구현기능

  1. 멤버ID와 멤버이름을 가진다.
  2. 생성시 멤버ID와 멤버이름을 설정한다.
  3. getMemberId 메서드 를 통해서 인스턴스의 멤버ID를 반환받는다.
  4. setMemberId 메서드를 통해서 인스턴스의 멤버ID를 설정한다.
  5. getMemberName 메서드를 통해서 인스턴스의 멤버이름을 반환받는다.
  6. setMemberName 메서드를 통해서 인스턴스의 멤버이름을 설정한다.
  7. 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를 활용해서 회원관리 프로그램을 만들어보자.
ArrayList의 메서드를 활용해서 회원을 추가하는 메서드, 삭제하는 메서드, 전체 회원을 출력하는 메서드를 만들었다.

구현 기능

  1. addMember 메서드로 맨마지막에 member을 추가하거나, 원하는 인덱스 값으로 member을 추가하는 기능 구현
  2. getMeber (int memberID) 메서드로 멤버ID를 가지고 멤버를 반환하는 기능 구현
    💡없는 경우에는 반환값에 null을 넣어 구현
  3. removeMember(int memberID) 메서드 로 멤버ID를 가진 멤버요소 삭제
  4. showAllMember() 메서드로 멤버 전체 출력

📒 MemberArrayList 구현

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를 쓰지 않는 이유?

 ArrayList를 직접 사용하는 것도 유효한 방법이지만, ArrayList를 활용하여 
 클래스를 작성하면 더 나은 모듈화, 확장성, 테스트 용이성, 코드 가독성을 얻을 수 있습니다.

1. 추상화와 모듈화

회원관리 데이터 저장, 삭제 등 관리에 대한 복잡한 로직을 클래스 
내부에 캡슐화할 수 있다.

2. 유연한 확장성

나중에 다른 자료구조로 변경하거나 데이터 저장 방식을 변경하는 등 확장이 쉬워진다.
ex) , ArrayList → LinkedList/Set

3. 기능 확장

회원 관리에 관련된 추가적인 기능을 제공할 수 있다.
중복 회원 검사, 회원 정보 정렬, 특정 조건에 따른 회원 검색 등의 기능을 
새로 추가하여 프로그램을 더 유용하게 만들수 있다. 
ArrayList만으로는 이런 구현은 불가능하다.

4. 코드 가독성

ArrayList를 직접 사용하는 것보다 클래스명과 메소드명을 통해 
코드의 의도를 명확하게 전달할 수 있다. 
이를 통해 코드의 가독성이 향상되고 유지보수가 가능해진다.

5. 좋은 설계 원칙 준수


ArrayList를 활용하면 SOLID 원칙과 같은 좋은 소프트웨어 설계 원칙을 준수할 수 있다.

📘 Vector 클래스

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 클래스

🤔 배열은 물리적 순서와 논리적 순서가 동일하다. 
따라서 중간에 자료를 삽입하거나 삭제하면, 나머지 자료를 이동시켜야 하고, 
처음 선언한 배열 크기 이상으로 요소가 추가되는 경우에는 크기가 더 큰 배열을 
새로 생성한다는 단점이 있다.

그에 비해서  LinkedList 클래스는 논리적 순서와 물리적 순서가 동일하지 않아서 삭제, 추가시에 더 편리하다.

📖 LinkedList의 구조

  • 각 요소는 요소의 정보(노드)와 다음 요소를 가리키는 주소 값을 가진다.
    다음 요소가 없는 마지막 요소의 경우는 주소 값에 null값이나 0을 가지게 된다.

링크드리스트에 요소 추가하기

  • A → B → D 에 3번째 자리에 C 추가하기
    👉 B요소의 주소 값을 C의 위치 값, C의 주소 값을 D의 위치 값
    A → B → C→ D

링크드리스트에 요소 제거하기

  • A → B → C→ D 에 B 삭제하기
    👉 A의 다음 요소를 D로 변경
    A → C→ D

👉 요소를 추가할 떄마다 동적으로 요소의 메모리를 생성하고, 추가하거 나 삭제할 때 편리하다.
하지만, 물리적으로 연결되어 있지 않아서 검색이 느리다는 단점이 있다.

🤔 ArrayList vs LinkedList

ArrayList : 자료의 변동이 거의 없고, 검색을 자주 해야할 때
LinkedList : 자료의 변동이 많고, 검색이 적을 때

📖 LinkedList의 메소드

✅ add메소드

메서드설명
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)의 객체를 주어진 객체로 바꾼다.

✅ LinkedList 배열 변환

메서드설명
Object[] toArray()LinkedList에 저장된 모든 객체들을 객체배열로 반환한다.
Object[] toArray(Obejct[] objArr)LinkedList에 저장된 모든 객체들을 객체배열 objArr에 담아 반환한다.

📒 LinkedList 순회 (이터레이터)

➕ List구조로 get(i)를 사용할 수 있지만 Iterator을 추천한다.

  • Collection 인터페이스를 상속받는 List나 Set 인터페이스에서도 iterator() 메소드를 사용할 수 있다. (Map은 X)

✅ 사용방법

  1. Collection을 구현한 LinkedList객체의 iterator() 메소드로 Iterator 객체를 반환한다. 이 객체를 통해 순환하는 것!!
  • Iterator<Member> ir = memberLink.iterator();
    memberLink라는 컬렉션에서 가져온 Iterator를 생성하고, 해당 Iterator의 요소 타입이 Member 클래스로 지정한다.
    Iterator ir = memberLink.iterator(); :
  • memberLink 컬렉션에서 가져온 Iterator를 생성하고, 제네릭 타입을 지정하지 않았습니다. 타입 안정성이 떨어질 수 있다.
  1. Iterator 객체의 메소드를 사용해 요소를 검색한다.
  • boolean hashNext() :
  • E next() : 다음에 잇는 요소를 반환한다.

✍️ 예시코드

<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);
        }
    }

🤔마무리하면서🤔

어렵고 복잡하다..ㅎ
profile
24년도까지 프로젝트 두개를 마치고 25년에는 개발 팀장을 할 수 있는 실력이 되자!

0개의 댓글