Рубрики
Без рубрики

Эффективная Java! Отдавайте предпочтение Универсальным Методам

Погружение в главу 30 “Эффективная Java”. Помеченный java, эффективный, универсальный, архитектура.

Эффективный обзор Java (Серия из 79 частей)

Глава этой недели продолжается с того места, на котором закончилась наша предыдущая глава. Если на прошлой неделе мы говорили об универсальных типах, то на этой неделе мы обсуждаем универсальные методы. Как и в случае с созданием универсальных типов, одной из основных целей использования универсальных методов является повышение читабельности и безопасности кода, что часто можно реализовать, заметив, что во время компиляции нет приведений и непроверенных предупреждений. Итак, давайте рассмотрим несколько примеров.

Давайте сначала рассмотрим метод, который не использует дженерики:

public static Set union(Set s1, Set s2) {
  Set result = new HashSet(s1);
  result.addAll(s2);
  return result;
}

Хотя приведенный выше код работает, он выдает предупреждения во время компиляции, поскольку не может обеспечить безопасность типов во время компиляции. Исправление немного простое. Мы добавляем список параметров типа, в котором объявляются параметры типа, которые будут использоваться между модификаторами метода и типом возвращаемого значения. Оттуда мы можем использовать параметр типа во всей функции. Давайте рассмотрим нашу вышеприведенную функцию в общем виде.

public static  Set union(Set s1, Set s2) {
  Set result = new HashSet<>(s1);
  result.addAll(s2);
  return result;
}

Это так просто, теперь мы избавились от наших предупреждений, а также обеспечили лучшую безопасность типов. Текущее ограничение функции объединение заключается в том, что тип трех наборов должен быть точно таким же, мы можем ослабить это требование, используя ограниченные типы подстановочных знаков , которые мы рассмотрим в следующей главе.

Еще одна возможность, которую мы имеем с универсальными методами, – это создание функций, которые предоставляют типизированные универсальные неизменяемые объекты. Поскольку дженерики реализуются с помощью удаления типов, мы можем иметь неизменяемый класс, который обслуживает все типы. Это одно из преимуществ удаления типа. Мы можем видеть примеры этого в JRE с помощью таких методов, как Collections.ReverseOrder и Коллекции.Пустой набор . Давайте рассмотрим пример этого. Давайте представим, что мы хотим реализовать нашу собственную функцию идентификации . Мы, конечно, не должны этого делать, потому что это уже существует, но это полезно учитывать.

private static UnaryOperator IDENTITY_FN = (t) -> t;

@SuppressWarnings("unchecked")
public static  UnaryOperator identityFunction() {
  return (UnaryOperator) IDENTITY_FN;
}

Нам действительно нужно сделать слепок но мы знаем, что это безопасно из-за того, что на рассматриваемом объекте на самом деле не происходит никаких действий, поэтому мы подавляем предупреждения.

Последнее, что нам следует рассмотреть, – это то, что называется привязкой к рекурсивному типу . Это происходит, когда параметр типа ограничен некоторым выражением, включающим сам тип. Это звучит более запутанно, чем есть на самом деле. Общее место, где это можно увидеть, используется в связи с интерфейсом Comparable . Тип T of Сопоставимый обозначает, с каким типом объекта можно сравнивать. На практике большинство типов просто сопоставимы сами с собой, таким образом Строка реализует Сопоставимый<Строка> и Целое число реализует Сопоставимый<Целое число> и так далее. Итак, в качестве примера привязки к рекурсивному типу давайте рассмотрим функцию, которая находит максимальное значение в коллекции.

public static > Optional max(Collection c) {
  E result = null;
  for (E e : c) {
    if (result == null || e.compareTo(result) > 0) {
      result = Objects.requireNonNull(e);
    }
  }
  return Optional.ofNullable(result);
}

Параметр типа можно прочитать как “любой тип E, который можно сравнить с самим собой”, что в конечном итоге является именно тем, что мы ищем. Хотя границы рекурсивного типа могут быть довольно сложными, надеюсь, вы сможете увидеть, как они могут быть полезны.

В целом, предпочтение универсальным методам и типам приводит к более безопасному коду, а также к более простому в использовании коду. Мы должны сделать все возможное, чтобы сделать наш код предупреждающим и свободным.

Эффективный обзор Java (Серия из 79 частей)

Оригинал: “https://dev.to/kylec32/effective-java-favor-generic-methods-344i”