제네릭(Generic)과 컬렉션 클래스(Collecrion Class)

권태형·2023년 3월 29일
0

지식정리

목록 보기
47/72
post-thumbnail
post-custom-banner

😀CS지식 관련 면접질문에 대해서 알아보면서 "제네릭이란 무엇이고, 컬렉션 클래스에서 왜 제네릭을 사용하지 설명해달라"는 질문을 보았다. 대충 구글링 해 본결과는 JAVA공화국인 한국에서 당연히 나올 수 있는 질문이었는데, 필자는 JAVA는 아직 손대 본 적도 없다. 나는 Javascript와 Node.js만 사용했었는데 이 포스팅을 정리하는 이유가 뭘까? 이유는 아래에서 설명하니 포스팅을 들여다보자.

제네릭(Generic)이란?

제네릭(Generic)은 C#과 Java와 같은 객체지향 프로그래밍에서 사용하는 기법으로, 한 번의 정의로 여러 종류의 데이터의 타입을 다룰 수 있도록 하는 방법을 말한다.

클래스나 메소드 내부에서 사용할 데이터 타입을 외부에서 지정하는 기법이다.
클래스나 인터페이스를 정의할 때 타입 매개변수(Type Parameter)를 사용하여 타입 안정성(Type Safety)을 보장하는 기능이다.

제네릭은 클래스나 메소드에서 사용할 내부 데이터 타입을 컴파일 시에 미리 지정하는 방법으로 데이터의 타입(data type)을 일반화한다(generalize)는 것을 의미한다.

제네릭을 사용하면 일반화된 타입 매개변수를 선언하고, 해당 매개변수를 사용하여 클래스나 메소드 내부에서 사용되는 데이터 타입을 지정한다.

😀간단한 검색의 제네릭의 정의를 알아보고 필자는 이 포스팅을 정리할 필요성을 느꼈다. 물론 Javascript에서는 Type을 지정하지 않는다. 하지만 TypeScript라면 어떨까? TypeScript또한 JAVA와 마찬가지로 제네릭을 사용할 수 있다.


사용방법(TypeScript)

제네릭은 보통 타입을 일반화하여 처리하는 방법을 사용한다.

// number 타입의 매개변수를 return하는 함수
function NumberReturnFunc(arg: number): number {
  return arg;
}

// string 타입의 매개변수를 return하는 함수
function StringReturnFunc(arg: string): string {
  return arg;
}

// boolean 타입의 매개변수를 return하는 함수
function BooleanReturnFunc(arg: boolean): boolean {
  return arg;
}

함수의 기능은 똑같은데, 매개변수의 타입과 반환하는 타입이 다르다는 이유로 여러 개의 함수를 만들어야 한다. 하지만 제네릭 기법을 사용하면 한 개의 함수로 구현할 수 있다.

function GenericReturnFunc<T>(arg: T): T {
  return arg;
}

⛔제네릭으로 일반화 시키는 타입의 명칭에 실상 어떤 문자를 넣어도 상관은 없지만, 명칭에 컨벤션이 존재하기 때문에 컨벤션에 유념하여 타입을 작성하도록 주의하자!

  • 일반화 시킨 타입 컨벤션
    • E(Element) : 요소, 예를 들어 List<E>
    • K(Key) : 키, 예를 들어 Map<K, V>
    • N(Number) : 숫자
    • T(Type) : 타입
    • V(Value) : 리턴 값 또는 매핑된 값
    • S, U, V : 2번째, 3번째 그리고 4번째에 선언된 타입

😀좀 더 다양한 사용방법과 자세한 내용을 알고 싶다면 출처 중타입스크립트 핸드북 링크가이드북 링크를 참고하자!


장점

  1. 클래스나 메소드 내부에서 사용되는 객체의 타입 안정성을 높일 수 있다.

  2. 반환값에 대한 타입 변환 및 타입 검사에 들어가는 노력을 줄일 수 있다.
    컴파일 타임에 타입 체크를 수행하기 때문에 런타임 에러를 줄일 수 있다.

  3. 코드의 재사용성이 높아진다.
    매개변수의 타입을 일반화 하여 여러 데이터 타입에서도 동일한 코드를 재사용할 수 있다.

    • ⛔사용자가 명시적으로 지정한 타입만 사용할 수 있도록 제한할 수도 있다.
      일반화 할 수 있지만, 반드시 일반화 하여야만 하는 것은 아니다.

단점

  1. 컴파일 시점에만 제공하고, 런타임 시점에는 형의 안정성을 제공하지 못한다.

예시(Typescript)

function getFirstElement<T>(arr: T[]): T {
  return arr[0];
}

const anyArr: any[] = [1, 'two', true];
const firstAny = getFirstElement(anyArr as number[]);
console.log(typeof firstAny); // 'number'

const anyArr2: any[] = [{ prop: 'value' }, 2, 'three'];
const firstAny2 = getFirstElement(anyArr2 as number[]);
console.log(typeof firstAny2); // 'object'

첫번째 const anyArr: any[] = [1, 'two', true]; 는 우연히 배열의 첫번째 요소가 1이라서 number타입이 정확이 나온 경우 이고, 두번째 const anyArr2: any[] = [{ prop: 'value' }, 2, 'three'];는 첫번째 요소가 객체이기 때문에 number로 캐스팅했음에도 불구하고 반환값은 any 타입이 되고, 결과는 객체가 나오게 되어 타입의 안전성을 보장할 수 없다.

만약 컴파일 과정에서 타입검사를 실시하지 않는 any 와 같은 타입으로 형변환을 하게 된다면, 타입의 안전성을 보장할 수 없게 된다.

  • 따라서 제네릭 함수를 사용할 때는 형 안정성을 보장하기 위해 any 타입 대신 명시적인 타입을 사용하거나, 입력값의 타입 검증을 통해 예기치 않은 동작을 방지해야한다.

컬렉션 클래스(Collecrion Class)

😀컬렉션 클래스를 알아보기전에 컬렉션이란 무엇인지 대해 먼저 알아보자

컬렉션(collection)이란 많은 수의 데이터를 그 사용 목적에 적합한 자료구조로 묶어 하나로 그룹화한 객체를 말한다.

😀그렇다면 컬렉션 클래스(Collecrion Class)는 뭘까? 컬렉션 클래스는 위의 컬렉션을 구현하는 데 사용되는 클래스를 의미한다.

컬렉션 클래스(Collection class)는 여러개의 값을 저장하고 관리하는 클래스를 말한다.
컬렉션의 구현을 돕기 위한 클래스를 말하며, 컬렉션은 데이터를 담을 수 있는 일종의 컨테이너를 말한다.


컬렉션 클래스의 종류

컬렉션 클래스에는 여러 종류가 있으며, 대표적으로 아래와 같은 종류가 있다.

  • 배열(Array)
    데이터를 일렬로 나열한 자료구조로, 인덱스를 이용하여 각 요소에 접근한다.

  • 리스트(List)
    데이터를 일렬로 나열한 자료구조로, 인덱스 대신 요소들 간의 링크를 이용하여 각 요소에 접근한다.

  • 스택(Stack)
    LIFO(Last-In-First-Out)의 자료구조로, 가장 나중에 추가된 요소가 가장 먼저 삭제된다.

  • 큐(Queue)
    FIFO(First-In-First-Out)의 자료구조로, 가장 먼저 추가된 요소가 가장 먼저 삭제된다.

  • 맵(Map)
    key-value 쌍의 자료구조로, 각 요소에는 key와 value가 존재하며 key를 이용하여 각 요소에 접근한다.

  • 집합(Set)
    중복되지 않는 요소들의 모임을 나타내는 자료구조, 삽입된 순서에 상관없이 저장되며, 또한 인덱스가 없어서 요소에 대한 접근을 할 때는 반복문해서 접근한다.

컬렉션 클래스의 간단한 예시 코드


사용시 장점

  • 동적으로 크기를 조정할 수 있으므로, 데이터의 추가/삭제가 쉽다.

  • 특정한 자료구조를 구현하기 위한 코드를 직접 작성하지 않아도 되므로 개발 시간이 절약된다.

  • 구현된 메소드를 활용하여, 데이터를 더 쉽게 검색, 정렬할 수 있다.

사용시 단점

  • 일부 컬렉션 클래스는 자바와 같은 언어에서는 느린 성능을 보일 수도 있다.
    이러한 경우에는 직접 구현한 자료구조를 사용하는 것이 더욱 효율적일 수 있을 것이다.

  • 컬렉션 클래스를 사용하기 위해서는 해당 언어의 라이브러리에 익숙해야 한다.
    이를 사용하는데 익숙하지 않은 경우에는 개발 시간이 더 오래 걸려 개발자가 소모하는 코스트가 많아 질 것이다.


컬렉션에서 제네릭을 사용하는 이유

😀컬렉션에서 제네릭을 사용하는 이유는 제네릭이 가지는 장점과 같다해도 무방하다.

  • 재사용성 증가
    제네릭 타입은 여러 타입의 파라미터를 삽입해 객체를 생성할 수 있기 때문에 코드를 간결하게 하고 재사용성을 높일 수 있다.
    동일한 기능을 하는 메서드에서 파라미터 타입만 다르게 사용할 경우, 제네릭 타입이 유용하게 쓰일 수 있다.

  • 컴파일 시 타입 에러 발견 가능
    제네릭 타입의 경우 컴파일시 잘못 사용되는 타입 문제점을 제거하기 위해 강하게 타입 체크를 수행한다.
    이덕분에 컴파일 이후 런타임 단계에서 타입 문제가 발생될 가능성을 방지해준다.

  • 컴파일러가 타입 변환 수행
    컴파일 단계에서 컴파일러가 타입 캐스팅을 수행해주기 때문에 불필요하게 코드에서 타입 캐스팅을 해줄 필요가 없다.


참고자료(출처)
TCP School JAVA 제네릭의 개념
티스토리 KADOSHoly [Java] 자바 - Collection이란? (컬렉션과 제네릭)
티스토리 DevStory [TypeScript]타입스크립트 제네릭 함수(Generic Function)
TypeScript HandBook Generic
타입스크립트 가이드북 제네릭과 함수
Velog edie_ko 포스팅 TypeScript | Generic 제네릭 (feat. TypeScript 두 달차 후기)

profile
22년 12월 개발을 시작한 신입 개발자 ‘권태형’입니다. 포스팅 하나하나 내가 다시보기 위해 쓰는 것이지만, 다른 분들에게도 도움이 되었으면 좋겠습니다. 💯컬러폰트가 잘 안보이실 경우 🌙다크모드를 이용해주세요.😀 지적과 참견은 언제나 환영합니다. 많은 댓글 부탁드립니다.
post-custom-banner

0개의 댓글