import java.util.*;
import java.util.function.Function;
class LegacyWildcards {
// legacy code
private static void foo
(Function
<String, Number
> func
) { // ...
}
// legacy code
private static void foo(List<Number> list) {
// ...
}
// legacy code
private static void foo(Comparator<Integer> comparator) {
// ...
}
// этот метод принимает на вход функцию с:
// - слишком широкой областью задания
// и
// - слишком конкретным множеством значений
@SuppressWarnings("unchecked")
private static <T, R> Function<T, R> vary(Function<? super T, ? extends R> f0) {
// здесь нам на руку работает type erasure:
// f0 превратится в объект raw типа Function,
// который кастить можно уже к чему угодно только лишь ценой warning'а
// (а warning можно подавить)
return (Function<T, R>) f0;
}
// кастит список вверх
@SuppressWarnings("unchecked")
private static <T> List<T> covary(List<? extends T> list) {
return (List<T>) list;
}
// кастит компаратор вниз
@SuppressWarnings("unchecked")
private static <T> Comparator<T> contravary(Comparator<? super T> comparator) {
return (Comparator<T>) comparator;
}
public static void main
(String[] args
) { Function<CharSequence, Integer> func = seq -> 1;
// ошибка, потому что генерики инвариантны
// foo(func);
// сработает, потому что будут же просто передаваться
// только строки, с которыми func значет, как справляться,
// потому что она может справляться с любыми CharSequence
//
// но это выглядит не очень
foo
((Function
<String, Number
>)(Function
<?,
?>) func
);
// так тоже сработает, потому что компилятор сам
// подставит правильные типы в лямбда-выражении, но
// это выглядит немного обскурно
foo(func::apply);
// тоже работает и немного лучше читается, потому что
// производится явный каст
// а ещё там есть некоторая защита, благодаря которой
// нельзя будет сделать небезопасный каст
foo(vary(func));
// то же самое можно делать с массивами, если
// тип, заданный в объявлении метода имеет слишком общий
// типовый параметр
List<Integer> intList = new ArrayList<>();
foo(covary(intList));
Comparator<Number> comparator = (n1, n2) -> 0;
foo(contravary(comparator));
}
}