메서드도 제네릭으로 만들 수 있는데, 매개변수화 타입을 받는 정적 유틸리티 메서드는 보통 제네릭이다.
예) Collections의 '알고리즘' 메서드(binarySearch, sort 등 ...)
public static Set union(Set s1, Set s2) {
Set result = new HashSet<>();
result.addAll(s2);
return result;
}
Unchecked call to 'HashSet(Collection<? extends E>)' as a member of raw type 'java.util.HashSet'
Unchecked call to 'addAll(Collection<? extends E>)' as a member of raw type 'java.util.Set'
타입 매개변수의 명명 규칙은 제네릭 메서드나 제네릭 타입이나 똑같다. (아이템 29, 68)
public static <E> Set<E> union(Set<E> s1, Set<E> s2) {
Set<E> result = new HashSet<>(s1);
result.addAll(s2);
return result;
}
경고 없이 컴파일되며, 타입 안전하고, 쓰기도 쉬운 메서드이다.
private static UnaryOperator<Object> IDENTITY_FN = (t) -> t;
@SuppressWarnings("unchecked")
public static <T> UnaryOperator<T> identityFunction() {
return (UnaryOperator<T>) IDENTITY_FN;
}
IDENTITY_FN을 UnaryOperator로 형변환하면 비검사 형변환 경고가 발생한다.
하지만 항등함수란 입력 값을 수정 없이 그대로 반환하는 특별한 함수이므로, T가 어떤 타입이든 UnaryOperator를 사용해도 타입 안전하다.
public static void main(String[] args) {
String[] strings = {"삼베", "대마", "나일론"};
UnaryOperator<String> sameString = identityFunction();
for (String s : strings) {
System.out.println(sameString.apply(s));
}
Number[] numbers = {1, 2.0, 3L};
UnaryOperator<Number> sameNumber = identityFunction();
for (Number n : numbers) {
System.out.println(sameNumber.apply(n));
}
}
public interface Comparable<T> {
int compareTo(T o);
}
public class RecursiveTypeBoundEx {
public static <E extends Comparable<E>> E max(Collection<E> c);
}
public static <E extends Comparable<E>> E max(Collection<E> collection) {
if (collection.isEmpty()) {
throw new IllegalArgumentException("컬렉션이 비어 있습니다.");
}
E result = null;
for (E e : collection) {
if (result == null || e.compareTo(result) > 0) {
result = Objects.requireNonNull(e);
}
}
return result;
}