Effective Java: Generics

Переходим к следующей главе книги. О том, что это за серия постов и зачем, можно прочитать в первом сообщении серии.

Item 23. Не используйте raw классы в новом коде.

Generic-и были добавлены в Java 1.5, чтобы сделать программы более безопасными и читаемыми. Поддержка raw-типов сохранилась только для обратной совместимости программ. При написании нового кода не стоит их использовать, так как это небезопасно.
Иногда воспользоваться generic-ами не представляется возможным, например, когда неизвестно, что будет лежать в передаваемой коллекции. Для этого случая в языке предусмотрены bounded и unbounded wildcard types.

Item 24. Не игнорируйте предупреждения компилятора об опасном преобразовании типов.
Чтобы написать по-настоящему безопасный код, который не будет порождать ошибки времени выполнения, нужно рассматривать каждое такое предупреждение компилятора.
Если избавиться от предупреждения по каким-либо причинами невозможно, но сам код точно безопасный, тогда (и только тогда) следует использовать аннотацию @SuppressWarnings("unchecked"), причём применять её нужно всегда на как можно меньший кусок кода. Рекомендуется к каждому использованию этой аннотации добавлять комментарий, объясняющий, почему код безопасен.

Item 25. Используйте списки (lists) вместо массивов.
Отмечается два важных отличия массивов и типизированных контейнеров.
  1. Массивы - ковариантны, Generic-и - инвариантны. Это значит, что если Sub - подкласс класса Super, то Sub[] - подкласс Super[], что неверно для типизированных классов. Это делает использование типизированных контейнеров более безопасным, чем использование массивов (хотя на первый взгляд кажется, что это только доставляет неудобства).
  2. Проверка типов для массивов происходит во время выполнения программы, а использование Generic-ов накладывает ограничения только на этапе компиляции, в рантайме же эта информация о типизации совершенно не используется (вернее сказать, её к этому времени просто уже нет).
В связи с этими фундаментальными различиями массивы и типизированные классы довольно плохо комбинируются. В большинстве случаев нужно вместо массивов использовать типизированные списки, жертвуя тем самым некоторой производительностью в пользу безопасности.

Item 26. Предпочитайте типизированные классы (generic types).
Generic-и - это хорошо, и если можно добавить их к классу, то нужно это сделать. В параграфе описывается процесс изменения класса для его типизации.

Item 27. Предпочитайте типизированные методы (generic methods).
Аналогично предыдущему параграфу. Отмечается удобство использования типизированных фабричных методов:
Map<String, List<String>> anagrams = newHashMap();
вместо
Map<String, List<String>> anagrams = new HashMap<String, List<String>>();
Generic-и могут быть рекурсивными.

Item 28. Используйте bounded wildcards для улучшения своего API.
Как было сказано выше, generic-и инвариантны, т.е. List<String> не является подклассом List<Object>. Иногда это доставляет серьёзные неудобства, но есть выход - bounded wildcards. Они бывают двух видов - "extends" и "super", каждый из которых покрывает, соответственно, все подклассы и все суперклассы указанного типа. Для того, чтобы быстро соображать, какой их них следует использовать, можно пользоваться т.н. правилом PECS: "PECS stands for producer-extends, consumer-super."
Не рекомендуется использовать wildcard-типы в качестве возвращаемых типов.

Item 29. Про безопасные гетерогенные контейнеры.
Типичное применение generic-ов (как в Collections API) ограничивает нас фиксированным числом типовых параметров контейнера. Это ограничение можно обойти, если типизировать не контейнер целиком, а только его ключ. В данном параграфе приводится пример написания такого безопасного контейнера, а также отмечаются некоторые особенности класса Class<T> как параметризированного типа.

Комментариев нет:

Отправить комментарий