Когда нужно использовать raw types?
Сначала вспомним, что такое raw type. В Java так называют generic-типы без указания типа-параметра. Такая языковая конструкция валидна, но в большинстве случаев приводит к предупреждению компилятора.
Предупреждение связано с риском получения проблемы heap pollution. Ей мы уже посвящали публикации ранее. Использование raw types никогда не оправдано – спецификация языка явно говорит: их поддержка остается только для обратной совместимости.
Есть всего три случая, когда использовать обобщенный тип без параметра правильно:
• Целевая версия Java < 5.0 (2002 год и ранее – вряд ли это ваш случай);
• В литерале класса. List.class не сработает, нужно писать List.class ;
• В операторе instanceof . Вместо instanceof Set должно быть instanceof Set .
Raw Types
A raw type is the name of a generic class or interface without any type arguments. For example, given the generic Box class:
public class Box < public void set(T t) < /* . */ >// . >
To create a parameterized type of Box , you supply an actual type argument for the formal type parameter T:
Box intBox = new Box<>();
If the actual type argument is omitted, you create a raw type of Box :
Box rawBox = new Box();
Therefore, Box is the raw type of the generic type Box . However, a non-generic class or interface type is not a raw type.
Raw types show up in legacy code because lots of API classes (such as the Collections classes) were not generic prior to JDK 5.0. When using raw types, you essentially get pre-generics behavior — a Box gives you Objects. For backward compatibility, assigning a parameterized type to its raw type is allowed:
Box stringBox = new Box<>(); Box rawBox = stringBox; // OK
But if you assign a raw type to a parameterized type, you get a warning:
Box rawBox = new Box(); // rawBox is a raw type of Box Box intBox = rawBox; // warning: unchecked conversion
You also get a warning if you use a raw type to invoke generic methods defined in the corresponding generic type:
Box stringBox = new Box<>(); Box rawBox = stringBox; rawBox.set(8); // warning: unchecked invocation to set(T)
The warning shows that raw types bypass generic type checks, deferring the catch of unsafe code to runtime. Therefore, you should avoid using raw types.
The Type Erasure section has more information on how the Java compiler uses raw types.
Unchecked Error Messages
As mentioned previously, when mixing legacy code with generic code, you may encounter warning messages similar to the following:
Note: Example.java uses unchecked or unsafe operations. Note: Recompile with -Xlint:unchecked for details.
This can happen when using an older API that operates on raw types, as shown in the following example:
public class WarningDemo < public static void main(String[] args)< Boxbi; bi = createBox(); > static Box createBox() < return new Box(); >>
The term "unchecked" means that the compiler does not have enough type information to perform all type checks necessary to ensure type safety. The "unchecked" warning is disabled, by default, though the compiler gives a hint. To see all "unchecked" warnings, recompile with -Xlint:unchecked.
Recompiling the previous example with -Xlint:unchecked reveals the following additional information:
WarningDemo.java:4: warning: [unchecked] unchecked conversion found : Box required: Box bi = createBox(); ^ 1 warning
To completely disable unchecked warnings, use the -Xlint:-unchecked flag. The @SuppressWarnings("unchecked") annotation suppresses unchecked warnings. If you are unfamiliar with the @SuppressWarnings syntax, see Annotations.
Когда нужно использовать raw types?
Как известно, raw type – это такие generic-типы, которые используются без задания типа-параметра. Данная конструкция допустима, но часто приводит к появлению warning от компилятора. Это связано с риском возникновения ситуации, которая называется heap pollution, это когда переменная, относящаяся к параметризированному типу, начинает ссылаться на непараметризированный объект. Применение raw type, в общем случае, недопустимо. Их поддержка в Java существует исключительно для поддержания совместимости с ранними версиями.
Оправдать применение обобщённого типа без параметров оправдано только в таких случаях:
- Используется Java 5 или более ранняя, выпущенная до 2002 года.
- В литерале class. Когда List.class не выполняется, тогда требуется писать List.class.
Если при использовании instanceof должно быть instanceof Set, а не instanceof Set.
Поделиться уроком
Обучающий бот с бесплатными тестами и практическими заданиями по Kotlin.
Курсовой проект – разработка Телеграм бота на Котлин для изучения иностранных слов. Включает: техническое задание, руководство по поэтапному написанию с код-ревью, работу с сетью и публикацию на сервере. И другие обучающие материалы в закрытом доступе.
Дженерики в Java для самых маленьких: синтаксис, границы и дикие карты
Разбираемся, зачем нужны дженерики и как добавить их в свой код.


Оля Ежак для Skillbox Media

Екатерина Степанова
Фулстек-разработчик. Любимый стек: Java + Angular, но в хорошей компании готова писать хоть на языке Ада.
У нас в парадной подъезде рядом с почтовыми ящиками стоит коробка. Предполагалось, что туда будут выбрасывать бумажный спам, который какие-то вредители упорно кладут в эти самые ящики. Но в коробке вместе с бумажками лежат пустые бутылки и банки, подозрительного вида пакеты, а в нынешних реалиях — ещё и использованные медицинские маски. Почему люди так делают? Потому что так можно.
Теперь представьте, что содержимое коробки вы отвозите на переработку, а перед этим каждый раз приходится отделять бумагу от прочего мусора. Не хотели бы вы заполучить такую коробку, которая не даст положить в себя что-то, кроме бумаги? Если ваш ответ «да» — вам понравятся дженерики (generics).
Содержание
- Знакомимся с дженериками
- Объявляем дженерик-классы и создаём их экземпляры
- Объявляем и реализуем дженерик-интерфейсы
- Пишем дженерик-методы
- Ограничиваем дженерики сверху и снизу
- Wildcards
- Собираем понятия, связанные с дженериками
Знакомимся с дженериками
До появления дженериков программисты могли неявно предполагать, что какой-то класс, интерфейс или метод работает с элементами определённого типа.
Посмотрите на этот фрагмент кода:

Паша быстро нашёл истинных виновников и попросил их исправить заполнение списка. Но на будущее решил подстраховаться от подобных ситуаций и переписал метод с использованием дженериков. Вот так:

Обратите внимание, что во второй версии Пашиного метода item не приводится насильно к типу String. Мы просто получаем в цикле очередной элемент списка, и компилятор соглашается, что это, очевидно, будет строка. Код стал менее громоздким, читать его стало проще.
Объявляем дженерик-классы и создаём их экземпляры
Давайте запрограммируем ту самую коробку, о которой шла речь в начале статьи: создадим класс Box, который умеет работать только с элементами определённого типа. Пусть для простоты в этой коробке пока будет только один элемент:

Собираем понятия, связанные с дженериками
Мы не успели разобраться с более сложными вещами — например, с заменами аргументов типов в классах-наследниках, с переопределением дженерик-методов, не узнали об особенностях коллекций с wildcards.
Обо всём этом и не только — в следующих статьях. А пока соберём небольшой словарик из терминов, которые связаны с использованием дженериков, — они пригодятся при чтении специальной литературы:
| Термин | Расшифровка |
|---|---|
| Дженерик-типы (generic types) | Дженерик-класс или дженерик-интерфейс с одним или несколькими параметрами в заголовке |
| Параметризованный тип (parameterized types) | Вызов дженерик-типа. Для дженерик-типа List параметризованным типом будет, например, List |
| Параметр типа (type parameter) | Используются при объявлении дженерик-типов. Для Box T — это параметр типа |
| Аргумент типа (type argument) | Тип объекта, который может использоваться вместо параметра типа. Например, для Box Paper — это аргумент типа |
| Wildcard | Обозначается символом «?» — неизвестный тип |
| Ограниченный wildcard (bounded wildcard) | Wildcard, который ограничен сверху — или снизу — |
| Сырой тип (raw type) | Имя дженерик-типа без аргументов типа. Для List сырой тип — это List |
Ещё больше о дженериках, коллекциях и других элементах языка Java узнайте на нашем курсе «Профессия Java-разработчик». Научим программировать на самом востребованном языке и поможем устроиться на работу.
Переменные ссылочного типа хранят адрес ячейки в памяти, в которой лежит значение этой переменной.
В этом их ключевое отличие от примитивных типов, когда в переменной хранится само значение.
Все ссылочные типы в Java наследуются от типа Object.