Raw types в Java: почему List без параметра опасен
💻 Информатика · 10 класс
Чем raw type отличается от diamond и List<Object>, как unchecked предупреждения превращаются в ошибки выполнения.

Что называется raw type
Raw type — использование имени обобщённого класса или интерфейса без аргументов типа. Например, List вместо List<String>. Механизм сохранён для совместимости со старым кодом, созданным до generics. Необобщённый класс сам по себе не является raw type: отсутствие угловых скобок у String не делает его «сырым».
Запись List<String> names = new ArrayList<>(); использует diamond справа, но сохраняет типизацию. Это отличается от List names = new ArrayList();. Пустые угловые скобки при выводе типа не равны полному отказу от параметров.
Как теряется проверка
import java.util.ArrayList;
import java.util.List;
List<String> words = new ArrayList<>();
words.add("cat");
List raw = words;
raw.add(17); // unchecked warning
String next = words.get(1); // ClassCastExceptionФрагмент выполняется внутри метода и намеренно демонстрирует ошибку. Words и raw ссылаются на один список. Через raw добавляется Integer, хотя типизированная ссылка обещает строки. При чтении второго элемента как String возникает ClassCastException.
Предупреждение компилятора — важная часть результата. Если просто отключить отображение unchecked, список не станет безопасным. Проблема не в интерфейсе IDE, а в нарушении обещанного типа содержимого.
Почему List<Object> — другое
List<Object> честно сообщает, что элемент при чтении имеет тип Object. Такой список может принимать строки и числа, а вызывающий код должен проверять конкретный тип. Raw type обходит часть проверок и способен испортить содержимое списка, на который уже есть типизированная ссылка.
При этом List<String> нельзя напрямую присвоить List<Object>. Иначе через ссылку Object можно было бы добавить число в список строк. Такое ограничение сохраняет безопасность. Для чтения списка неизвестного типа существует List<?>, но это ещё одна конструкция со своими правилами записи.
Когда встречаются предупреждения
Старый API может возвращать raw List. При присваивании его результата List<String> компилятор не может доказать безопасность всех элементов и выдаёт unchecked conversion. Нужно выяснить контракт API, проверить содержимое и по возможности обновить интерфейс. Одно явное приведение не проверяет автоматически тип каждого элемента коллекции.
Для подробной диагностики используют параметр javac -Xlint:unchecked. Аннотация SuppressWarnings не исправляет данные и должна сопровождать только обоснованную локальную гарантию. Новичку полезнее сначала устранить причину предупреждения.
Разобранный безопасный вариант
Если список должен хранить строки, объявляем обе ссылки с List<String> и добавляем только строки. Попытка add(17) тогда отклоняется при компиляции, до запуска. Если по смыслу нужны разные типы, проектируем List<Object> и явно обрабатываем Object, не обещая String.
Практика
- Является ли new ArrayList<>() raw type при типизированном контексте?
- В какой момент пример ломается: при add(17) или при чтении как String?
- Исправляет ли SuppressWarnings неподходящий Integer?
Ответы
1. Нет: diamond позволяет вывести аргумент типа. 2. Проверяемый сбой происходит при чтении второго элемента как String; добавление через raw сопровождалось предупреждением. 3. Нет: аннотация влияет на диагностику, а не превращает число в строку и не восстанавливает нарушенный контракт.