[JAVA] 제네릭타입과 람다식
제네릭 타입
클래스, 인터페이스, 메소드를 정의할 때 타입 매개변수(타입 파라미터)를 선언하고 사용할수 있음
- 장점
- 여러 유형에 걸쳐 동작하는 일반화된 클래스나 메소드를 정의할 수 있음
- 자료형을 한정함으로써 컴파일 시점에 자료형 검사가 가능
- 캐스트(형변환) 연산자의 사용이 불필요
- 예시 )
class ArrayList<E> implement List<E> {
- 예시 )
boolean add (E e)
- 예시 )
E get (int index)
- 여러 유형에 걸쳐 동작하는 일반화된 클래스나 메소드를 정의할 수 있음
- 특징
- 클래스 정의에서 타입 파라미터를 선언함, 클래스를 사용할때는 타입 명시
- 타입 파라미터는 참조형만 가능함
- 필드의 자료형 메소드 반환형, 인자의 자료형으로 사용할 수 있음
- 필드의 자료형 메소드 반환형, 인자의 자료형으로 사용할 수 있음
- 컴파일 할 때, 명확한 타입 검사를 수행할 수 있음
- 메소드 호출 시 인자의 유형이 맞는지
- 메소드 호출의 결과를 사용할 때 유형이 맞는지
- 메소드 호출 시 인자의 유형이 맞는지
- 자료형을 매개변수로 가지는 클래스와 인터페이스를 제네릭 타입이라고 함
- 클래스 정의에서 타입 파라미터를 선언함, 클래스를 사용할때는 타입 명시
- 문법
- class 클래스이름 <T1, T2, … > { … }
- 클래스 정의에서 클래스 이름의 오른편 <>안에 타입 파라미터를 표시함
- 컴마(,)로 구분하여 여러 개의 타입 파라미터를 지정할 수 있음
- 타입 파라미터는 타입을 전달 받기 위한 것
- 타입 파라미터의 이름은 관례적으로 E,K,V,N,T … 을 사용함
- 제네릭 타입을 사용하지 않으면 컴파일 시점에서 오류를 검출하지 못함
- 의미가 명확하면 생성자 호출 시, 괄호만 사용할 수 있음
Data<String> b3 = new Data<>();
- class 클래스이름 <T1, T2, … > { … }
- Raw 타입
- 제네릭 타입이지만 일반 타입처럼 사용하는 경우, 제네릭 타입을 지칭하는 용어
- 타입 매개변수 없이 사용되는 제네릭 타입
- 자료형을 Object로 처리함
- 예시 )Data2 data = new Data2("hello");
- 이때 Data2는 제네릭타입 Data2
의 raw타입
- 제네릭 타입이지만 일반 타입처럼 사용하는 경우, 제네릭 타입을 지칭하는 용어
- 자료형을 매개변수로 가지는 메소드
- 하나의 메소드 정의로 여러 유형의 데이터를 처리할 때 유용
- 메소드 정의에서 반환형 왼편 <>안에 타입 매개변수를 표시
- 타입 매개변수를 메소드의 반환형이나 메소드 매개변수의 자료형, 지역 변수의 자료형으로 사용할 수 있음
- 예시 )
public static <T> T getLast(T[] a) {
- 예시 )
- 인스턴스 메소드와 static 메소드 모두 제네릭 메소드로 정의 가능
- 제네릭 메소드를 호출할 때, 타입을 명시하지 않아도 인자에 의해 추론이 가능
- 하나의 메소드 정의로 여러 유형의 데이터를 처리할 때 유용
- 제네릭의 타입 제한
- 자료형을 매개변수화하여 클래스/인터페이스/메소드를 정의할 때, 적용 가능한 자료형에 제한을 두는 것
-
와 같이 하면 T를 상한으로 정할 수 있음
- T에 주어지는 자료형은 Number의 서브 클래스여야 함
- T에 주어지는 자료형은 Number의 서브 클래스여야 함
- 자료형을 매개변수화하여 클래스/인터페이스/메소드를 정의할 때, 적용 가능한 자료형에 제한을 두는 것
- 제네릭 타입과 형변환
- 상속 관계가 있어야 상위/하위 자료형의 관계가 존재함
- 예시 )
class FormattedData<T> extends Data<T>
라면Data<Integer> data = new FormattedData<Integer>()
가능
- 예시 )
- 타입간의 상위/하위 관계는 무관함
Data<Number> data = new Data<Integer>()
는 불가능. 상하위 관계가 없음
- 상속 관계가 있어야 상위/하위 자료형의 관계가 존재함
- 유의사항
- 기본자료형은 타입 매개변수로 지정할 수 없음
Data<int>
는 오류
- 타입 매개변수로 객체 생성을 할 수 없음
class Data<T> {private T t1 = new T(); }
는 오류
- 타입 매개변수의 타입으로 static 데이터 필드를 선언할 수 없음
class Data <T> { private static T t2; }
는 오류
- 제네릭 타입의 배열을 선언할 수 없음 Data<Integer>[] arrayOfData;
는 오류
- 기본자료형은 타입 매개변수로 지정할 수 없음
람다식
- 인터페이스를 구현하는 익명 클래스의 객체 생성 부분을 수식화 한 것
-
구현할 것이 1개의 추상 메소드 뿐일 때 간단히 표현할 수 있음
- 람다식 구분
- 메소드 매개변수의 괄호, 화살표, 메소드 몸체로 표현
인터페이스 객체변수 = (매개변수목록) -> {실행문 목록}
- 메소드 매개변수의 괄호, 화살표, 메소드 몸체로 표현
- 기본 문법
- 익명 구현 클래스의 객체 생성 부분만 람다식으로 표현함
- 익명 서브 클래스의 객체 생성은 람다식이 될 수 없음
- 익명 서브 클래스의 객체 생성은 람다식이 될 수 없음
- 이때 인터페이스에는 추상 메소드가 1개만 있어야 함
- 2개 이상의 추상 메소드를 포함하는 인터페이스는 사용 불가
- 2개 이상의 추상 메소드를 포함하는 인터페이스는 사용 불가
- 람다식의 결과 타입을 타깃 타입이라고 함
- 1개의 추상 메소드를 포함하는 인터페이스를 함수적 인터페이스라 함
- 메소드가 1개 뿐이므로 메소드 이름을 생략할 수 있음
- 람다식은 이름 없는 메소드 선언과 유사함
- 메소드가 1개 뿐이므로 메소드 이름을 생략할 수 있음
- 매개변수 목록에서 자료형은 인터페이스(타깃타입) 정의에서 알 수 있으므로 자료형을 생략하고 변수 이름만 사용 가능
- 매개변수가 1개면 괄호도 생략 가능하며 변수 이름 하나만 남음
- 매개변수를 가지지 않으면 괄호만 남음
- 화살표 사용
- 실행문 목록에서 실행문이 1개면 중괄호 생략 가능
- 실행문이 return문 뿐이라면 return과 세미콜론, 중괄호를 동시 생략하고 1개의 수식만 남게 됨
- 익명 구현 클래스의 객체 생성 부분만 람다식으로 표현함
- 람다식의 활용
- 함수적 인터페이스
- 1개의 추상 메소드만 가지는 단순한 인터페이스를 함수적 인터페이스라 함
- 패키지 java.util.function에서 표준 함수적 인터페이스가 제네릭 인터페이스로 제공됨
- 함수적 인터페이스를 구현하는 클래스를 정의할 때, 익명 클래스 정의를 활용할 수 있으나 람다식이 효율적
- 표준 함수적 인터페이스의 예
- Consumer
는 void accept(T t)를 가짐 - Supplier
는 T get() 메소드를 가짐 - Function<T, R>은 R apply(T t)를 가짐
- Consumer
- 함수적 인터페이스