티스토리 뷰

Collection 인터페이스

 지금 구현하던 Collections 프레임워크들은 Collection 인터페이스 내에 상속되어 구현된 클래스들이다.

 처음에는 구현 자체에만 목적을 가지고 ArrayList, LinkedList 등을 만들었지만 구현 양이 늘어남에 따라 서로 같은 기능을 가진 메소드들이 반복적으로 나타났다. 따라서 더 구현하기 전에 Collection 인터페이스를 정의하고 메소드들의 기능에 대해서 정리하기로 하였다.

 

 먼저 각 클래스들이 공통으로 가지는 메소드들을 확인해보자.

  • size()
  • isEmpty()
  • contains()
  • toArray()
  • add()
  • remove()
  • clear()

가 있다. 따라서 Collection 인터페이스를 만들어서 정의해보자.

package DataStructure;

public interface Collection<E> {
    
    int size();

    boolean isEmpty();

    boolean contains(Object o);

    Object[] toArray();

    <T> T[] toArray(T[] a);

    boolean add(E e);

    void add(int index, E element);

    boolean remove(Object o);

    E remove(int index);

    void clear();
}

 

 최상위 인터페이스인 Collection을 생성하였기 때문에 List, Queue(Set은 다음에 만들때 상속한다)는 이를 상속해준다.

public interface List<E> extends Collection<E>
public interface Queue<E> extends Collection<E>

 그럼 이제 위 Collection의 메소드는 List, Queue가 공통으로 상속받게 되며 굳이 이 메소드들을 각 인터페이스에서 또 정의하지 않더라도 Collection 인터페이스 아래에 있는 모든 클래스들은 이 메소드들을 구현해야한다.

 

총정리하면 Collection 프레임워크는 다음 모습을 띈다.

Collection 프레임워크 전체 구조

 

add() vs offer()??

 Collection프레임워크들을 정리해놓고 보니 눈에 띄는 메소드 둘은 add()와 offer()이다. 분명 둘의 기능은 동일하다. List의 가장 마지막 index에 값을 더한다. 근데 같은 이름의 메소드가 굳이 필요할까?

 메소드 실행이 불가할 때 무엇을 return 하느냐의 차이다.

 아래는 오라클 docs에서 발췌한 내용이다.


 사실 구현내용에서 이를 따로 포함하여 구현하지는 않았지만 Queue는 위와 같이 add, remove, element() 메소드가 존재한다. 잘보면 Queue의 구현 메소드에서 왼쪽 메소드는 Exception을 반환하고, 오른쪽 메소드는 special value를 반환한다고 한다.

 즉 remove() 메소드는 제거될 때 Queue가 비어있어서 remove()를 실패하면 Exception이 발생되고 poll()은 구현을 해서 알겠지만 null이 리턴된다.

 

public E remove() {
    return removeFirst();
}

public E removeFirst() {
    final LinkedList.Node<E> f = first;
    if (f == null)
        throw new NoSuchElementException();
    return unlinkFirst(f);
}

public E poll() {
    final LinkedList.Node<E> f = first;
    return (f == null) ? null : unlinkFirst(f);
}

 Queue에서 사용하는 remove()메소드와 poll() 메소드는 Queue의 최상단을 제거하는 같은 기능을 제공하는 메소드이지만, Queue가 비어서 제거할 값이 없을 경우 Exception을 처리하거나 null을 반환하거나의 차이인 것이다.

 

 element()peek()메소드도 마찬가지다.

public E element() {
    return getFirst();
}

public E getFirst() {
    final Node<E> f = first;
    if (f == null)
        throw new NoSuchElementException();
    return f.item;
}

public E peek() {
    final Node<E> f = first;
    return (f == null) ? null : f.item;
}

 가장 최상단의 값을 가져오는 이 두 메소드는 실패하는 경우가 Queue가 비어있는 경우이다. 반환값 처리의 차이가 있다고 했기 때문에 element()가 실패하는 경우 Exception이, peek()가 실패했을 경우 null이 반환되는 것을 확인할 수 있다.

 

 

지금부터는 offer()메소드에 Exception이 들어간 내용을 담고 있습니다. 단 Exception이 나온 내용에 대해서 개인적인 생각을 많이 담고 있기 때문에 틀린 부분이 있을 수 있습니다. 쓴 내용에 틀린점이 있다거나 정확한 내용을 아시는 분은 댓글 남겨주시면 바로 피드백하겠습니다.

 근데 이 docs를 보면서 느낀건 조금 이상하다였다.

 분명 docs 홈페이지 상에서는 add()offer()의 차이는 더하는 것이 실패했을 때 Exception이 발생하느냐, 다른 special value가 return 되느냐 였다. 그럼 offer()는 Exception이랑 차이가 없어야 할 것이다.

 근데... 실제 Queue 인터페이스를 들어가면 말이 좀 다르다.

offer return이 false이긴한데 exception이 있다.

 return에는 false를 반환한다고 하긴했는데 offer()도 Exception을 처리한다고 나와있다. 즉 실제 클래스상에서는 Exception처리를 했다는 설명인데 offer 메소드 구현부를 보자.

add와 offer 모두 같은 구현부를 가지고 있다.

 Exception을 직접 처리하지는 않는데 offer()메소드는 add()메소드를 호출했기 때문에 그냥 똑같은 메소드이다. 아니 그럼 docs가 틀린건가?

 꼭 그런것만은 아니라고 생각한다. add()offer()가 등장한 이유를 생각해보면 List구조에서 "더하는" 메소드를 진행했을 때 언제 에러가 날까? 용량(capacity)이 제한될 때이다.

 ArrayList와 LinkedList의 차이에 대해서 다시 넘어와서 생각해보면 동적 배열과 연결된 Node의 집합이다. LinkedList는 메모리의 한계치에 닿지않은 이상 Node를 계속해서 생성할 수 있지만 ArrayList는 배열이라는 한계 때문에 사실 MAX_ARRAY_SIZE라는 상수로 제한해두고 있다.

private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;

 즉, Collection 프레임워크에서 특정 요소를 더하는 add()라는 메소드를 만들 때 Exception이 일어날 것을 알고 있었다. 하지만 LinkedList의 "더하는" 메소드는 add()를 사용해도 됐지만 ArrayList 때와는 동일한 Exception이 일어날 수가 없다. 그래서 생겨난 것이 offer()라고 생각한다.

 

 기본적으로 ArrayList와 LinkedList등의 모든 Collection 프레임워크에 모두 통용되는 add() 메소드에는 공통적으로 실패시 Exception이라는 조건을 달고, 예외적으로 LinkedList와 같이 같은 Exception에 걸리지 않을 법한 클래스들을 위해서 offer() 메소드를 만들었다고 생각한다.

 

 그래도 add와 offer의 차이를 이야기할 때는 둘의 설계 이유에 따라

 이 그림을 보여주며 실패했을 때는 Exception을 처리하는가 special value를 처리하는가로 나뉜가로 이야기하자.

'자료구조' 카테고리의 다른 글

[JAVA] Deque 직접 구현하기  (0) 2021.04.20
[JAVA] Queue 직접 구현하기  (1) 2021.04.20
[JAVA] Stack 직접 구현하기  (0) 2021.04.16
[JAVA] LinkedList 직접 구현하기  (1) 2021.03.22
[JAVA] ArrayList 직접 구현하기  (2) 2021.03.19
댓글
최근에 올라온 글
Total
Today
Yesterday