fork(1) download
  1. import java.util.*;
  2. import java.util.function.Function;
  3.  
  4. class LegacyWildcards {
  5. // legacy code
  6. private static void foo(Function<String, Number> func) {
  7. // ...
  8. }
  9.  
  10. // legacy code
  11. private static void foo(List<Number> list) {
  12. // ...
  13. }
  14.  
  15. // legacy code
  16. private static void foo(Comparator<Integer> comparator) {
  17. // ...
  18. }
  19.  
  20. // этот метод принимает на вход функцию с:
  21. // - слишком широкой областью задания
  22. // и
  23. // - слишком конкретным множеством значений
  24. @SuppressWarnings("unchecked")
  25. private static <T, R> Function<T, R> vary(Function<? super T, ? extends R> f0) {
  26. // здесь нам на руку работает type erasure:
  27. // f0 превратится в объект raw типа Function,
  28. // который кастить можно уже к чему угодно только лишь ценой warning'а
  29. // (а warning можно подавить)
  30. return (Function<T, R>) f0;
  31. }
  32.  
  33. // кастит список вверх
  34. @SuppressWarnings("unchecked")
  35. private static <T> List<T> covary(List<? extends T> list) {
  36. return (List<T>) list;
  37. }
  38.  
  39. // кастит компаратор вниз
  40. @SuppressWarnings("unchecked")
  41. private static <T> Comparator<T> contravary(Comparator<? super T> comparator) {
  42. return (Comparator<T>) comparator;
  43. }
  44.  
  45. public static void main(String[] args) {
  46. Function<CharSequence, Integer> func = seq -> 1;
  47. // ошибка, потому что генерики инвариантны
  48. // foo(func);
  49.  
  50. // сработает, потому что будут же просто передаваться
  51. // только строки, с которыми func значет, как справляться,
  52. // потому что она может справляться с любыми CharSequence
  53. //
  54. // но это выглядит не очень
  55. foo((Function<String, Number>)(Function<?, ?>) func);
  56.  
  57. // так тоже сработает, потому что компилятор сам
  58. // подставит правильные типы в лямбда-выражении, но
  59. // это выглядит немного обскурно
  60. foo(func::apply);
  61.  
  62. // тоже работает и немного лучше читается, потому что
  63. // производится явный каст
  64. // а ещё там есть некоторая защита, благодаря которой
  65. // нельзя будет сделать небезопасный каст
  66. foo(vary(func));
  67.  
  68. // то же самое можно делать с массивами, если
  69. // тип, заданный в объявлении метода имеет слишком общий
  70. // типовый параметр
  71. List<Integer> intList = new ArrayList<>();
  72. foo(covary(intList));
  73.  
  74. Comparator<Number> comparator = (n1, n2) -> 0;
  75. foo(contravary(comparator));
  76. }
  77. }
Success #stdin #stdout 0.08s 33620KB
stdin
Standard input is empty
stdout
Standard output is empty