Що таке сирий тип, і чому ми не повинні його використовувати?


662

Запитання:

  • Що таке сировинні Java, і чому я часто чую, що їх не слід використовувати в новому коді?
  • Яка альтернатива, якщо ми не можемо використовувати сировинні типи, і як це краще?

Підручники Java все ще використовують JComboBox, який викликає це попередження. Яка версія комбобоксу не спричинить це попередження? docs.oracle.com/javase/tutorial/uiswing/components/…
SuperStar

1
Зауважте, що причина існування сировинних типів полягає в зворотній сумісності з Java 1.4 і новішими версіями, які взагалі не мали генеричних даних.
Джеспер

Відповіді:


744

Що таке сировина?

Специфікація мови Java визначає необроблений тип наступним чином:

JLS 4.8 Види сировини

Сирий тип визначається як один із:

  • Тип посилання, який формується шляхом взяття назви загального декларації типу без супровідного списку аргументів типу.

  • Тип масиву, тип елемента якого є необробленим.

  • Нечлений staticтип необробленого типу, Rякий не успадковується від суперкласу або надінтерфейсу R.

Ось приклад для ілюстрації:

public class MyType<E> {
    class Inner { }
    static class Nested { }

    public static void main(String[] args) {
        MyType mt;          // warning: MyType is a raw type
        MyType.Inner inn;   // warning: MyType.Inner is a raw type

        MyType.Nested nest; // no warning: not parameterized type
        MyType<Object> mt1; // no warning: type parameter given
        MyType<?> mt2;      // no warning: type parameter given (wildcard OK!)
    }
}

Тут, MyType<E>є параметризованим типом ( JLS 4.5 ). Це звичайно розмовно називати цей тип просто MyTypeкоротким, але технічно це ім'я MyType<E>.

mtмає необроблений тип (і генерує попередження про компіляцію) першою точкою кулі у наведеному вище визначенні; innтакож має необроблений тип по третій кулі.

MyType.Nestedне є параметризованим типом, хоча це тип типу параметризованого типу MyType<E>, тому що це static.

mt1, і mt2вони оголошені з фактичними параметрами типу, тому вони не є необробленими.


Що такого особливого у сировинних видах?

По суті, сировинні типи поводяться так, як були до введення дженериків. Тобто, наступне є повністю законним під час компіляції.

List names = new ArrayList(); // warning: raw type!
names.add("John");
names.add("Mary");
names.add(Boolean.FALSE); // not a compilation error!

Вищеописаний код працює чудово, але припустимо, у вас є також наступне:

for (Object o : names) {
    String name = (String) o;
    System.out.println(name);
} // throws ClassCastException!
  //    java.lang.Boolean cannot be cast to java.lang.String

Тепер ми стикаємося з проблемою під час виконання, оскільки namesмістить щось, що не є instanceof String.

Імовірно, якщо ви хочете , namesщоб утримувати тільки String, ви могли б , можливо , по- , як і раніше використовувати необроблений тип і вручну перевірити всі add самостійно, а потім вручну відливати до Stringкожного елементу з names. Ще краще , хоча НЕ використовувати сирий тип і дозволити компілятору виконати всю роботу за вас , використовуючи потужність Java generics.

List<String> names = new ArrayList<String>();
names.add("John");
names.add("Mary");
names.add(Boolean.FALSE); // compilation error!

Звичайно, якщо ви дійсно хочете namesдозволити a Boolean, ви можете оголосити це якList<Object> names і наведений вище код компілюватиметься.

Дивись також


Як сирий тип відрізняється від використання <Object> в якості параметрів типу?

Нижче наведено цитату з Ефективного другого видання Java, пункт 23: Не використовуйте необроблені типи в новому коді :

Тільки в чому різниця між необробленим типом Listі типовим параметром List<Object>? Якщо говорити вільно, перший відмовився від загальної перевірки типів, а другий чітко сказав компілятору, що він здатний містити об'єкти будь-якого типу. Хоча ви можете передати List<String>параметр типу List, ви не можете передати його параметру типу List<Object>. Існують правила List<String>підтипу для дженериків і є підтипом необробленого типу List, але не параметризованого типу List<Object>. Як наслідок, ви втрачаєте безпеку типу, якщо використовуєте сировинний тип типу List, але не, якщо ви використовуєте параметризований тип типуList<Object> .

Для ілюстрації пункту розглянемо наступний метод, який приймає a List<Object>та додає a new Object().

void appendNewObject(List<Object> list) {
   list.add(new Object());
}

Генеріки на Яві інваріантні. A List<String>не є List<Object>, тому наступне створює попередження компілятора:

List<String> names = new ArrayList<String>();
appendNewObject(names); // compilation error!

Якби ви оголосили appendNewObjectвзяти необроблений тип Listяк параметр, це буде компілюватися, і ви втратили б безпеку типу, яку ви отримуєте з дженериків.

Дивись також


Чим тип сировини відрізняється від використання <?>в якості параметра типу?

List<Object>, List<String>і т. д. все List<?>, тому може бути спокусливо просто сказати, що вони просто Listзамість цього. Однак є основна відмінність: оскільки List<E>визначає лише те add(E), ви не можете додати будь-який довільний об'єкт до List<?>. З іншого боку, оскільки необроблений тип Listне має безпеки типу, ви можете addмайже все, що завгодноList .

Розглянемо наступну варіацію попереднього фрагмента:

static void appendNewObject(List<?> list) {
    list.add(new Object()); // compilation error!
}
//...

List<String> names = new ArrayList<String>();
appendNewObject(names); // this part is fine!

Компілятор зробив чудову роботу, захистивши вас від потенційного порушення типової інваріантності List<?>! Якби ви оголосили параметр як необроблений тип List list, код буде компілюватися, і ви порушили б інваріант типу List<String> names.


Сирий тип - це стирання цього типу

Повернутися до JLS 4.8:

Можна використовувати як тип стирання параметризованого типу або стирання типу масиву, тип елемента якого є параметризованим типом. Такий тип називається сировинним типом .

[...]

Надкласи (відповідно, суперінтерфейси) необробленого типу - це стирання надкласів (суперінтерфейсів) будь-якого з параметрів параметрів загального типу.

Тип конструктора, методу екземпляра або неполевого staticтипу необробленого типу, Cякий не успадковується від його суперклассів або надінтерфейсів, є типовим типом, який відповідає стирання його типу в загальній декларації, що відповідає C.

Простіше кажучи, при використанні необробленого типу конструктори, методи екземплярів і не staticполя також стираються .

Візьмемо такий приклад:

class MyType<E> {
    List<String> getNames() {
        return Arrays.asList("John", "Mary");
    }

    public static void main(String[] args) {
        MyType rawType = new MyType();
        // unchecked warning!
        // required: List<String> found: List
        List<String> names = rawType.getNames();
        // compilation error!
        // incompatible types: Object cannot be converted to String
        for (String str : rawType.getNames())
            System.out.print(str);
    }
}

Коли ми використовуємо сире MyType, воно також getNamesстирається, так що воно повертає сировину List!

JLS 4.6 продовжує пояснювати наступне:

Стирання типу також відображає підпис конструктора або методу до підпису, який не має параметризованих типів або змінних типів. Стирання підпису конструктора або методу s- це підпис, що складається з однойменної назви sта стирання всіх формальних типів параметрів, наведених у s.

Тип повернення методу та параметри типу загального методу чи конструктора також зазнають стирання, якщо метод або підпис конструктора стираються.

Видалення підпису загального методу не має параметрів типу.

Наступний звіт про помилки містить деякі думки Мауріціо Цімадамора, розробника компілятора, та Алекса Баклі, одного з авторів JLS, про те, чому має відбуватися така поведінка: https://bugs.openjdk.java.net/browse / JDK-6400189 . (Коротше кажучи, це робить специфікацію простішою.)


Якщо це небезпечно, чому дозволено використовувати необроблений тип?

Ось ще одна цитата JLS 4.8:

Використання сировинних типів допускається лише як поступка сумісності застарілого коду. Використання необроблених типів у коді, написаному після введення загальної мови в мову програмування Java, сильно не рекомендується. Можливо, що майбутні версії мови програмування Java не дозволять використовувати необроблені типи.

Ефективне Java 2nd Edition також має додати:

Зважаючи на те, що ви не повинні використовувати необроблені типи, чому мовні дизайнери дозволили їх? Для забезпечення сумісності.

Платформа Java збиралася вступити у своє друге десятиліття, коли були представлені дженерики, і існувала величезна кількість коду Java, який не використовував дженерики. Вважалося критичним, що весь цей код залишається законним та сумісним із новим кодом, який використовує дженерики. Потрібно було легально передавати екземпляри параметризованих типів методам, призначеним для використання із звичайними типами, і навпаки. Ця вимога, відома як сумісність з міграцією , зумовила рішення щодо підтримки сировинних типів.

Підводячи підсумок, в новому коді НІКОЛИ не слід використовувати сирі типи. Ви завжди повинні використовувати параметризовані типи .


Чи немає винятків?

На жаль, оскільки дженерики Java не повторно змінені, є два винятки, коли в новому коді повинні використовуватися необроблені типи:

  • Дослідники класу, наприклад List.class, ніList<String>.class
  • instanceofоперанд, наприклад o instanceof Set, ніo instanceof Set<String>

Дивись також


16
Що ви маєте на увазі, що "дженерики Java не повторні"?
Карл Г

7
За другим винятком, синтаксис o instanceof Set<?>також може уникати необробленого типу (хоча в цьому випадку він є лише поверхневим).
Пол Беллора

1
Типи сировини дуже корисні і зменшують код котла у випадку пошуку JNDI для квасолі, яка розширює інтерфейс. Це вирішує необхідність запису nвіддалених бобів для кожного класу реалізації з однаковим кодом.
djmj

8
"Нереалізований" - це ще один спосіб сказати, що вони стираються. Компілятор знає, що таке загальні параметри, але ця інформація не передається генерованому байтовому коду. JLS вимагає, щоб літерали класу не мали параметрів типу.
Ерік Г. Хагстром

2
@OldCurmudgeon Це цікаво. Я маю на увазі, що офіційно це не є жодним , тому що літеральний клас визначається як просто TypeName.class, де TypeNameпростий ідентифікатор ( jls ). Якщо говорити гіпотетично, то, мабуть, це справді могло бути і те, і інше. Можливо, як підказка List<String>.classє варіант, який JLS спеціально викликає помилку компілятора, тож якщо вони коли-небудь додадуть його до мови, я б очікував, що це саме те, що вони використовують.
Radiodef

62

Що таке сировинні Java, і чому я часто чую, що їх не слід використовувати в новому коді?

Типи сировини - це давня історія мови Java. На початку були Collectionsі вони Objectsне тримали нічого більше і нічого менше. Кожна операція на Collectionsнеобхідних ролях від Objectпотрібного типу.

List aList = new ArrayList();
String s = "Hello World!";
aList.add(s);
String c = (String)aList.get(0);

Хоча це працювало більшу частину часу, помилки траплялися

List aNumberList = new ArrayList();
String one = "1";//Number one
aNumberList.add(one);
Integer iOne = (Integer)aNumberList.get(0);//Insert ClassCastException here

Старі типові колекції не могли забезпечити безпеку типу, тому програмісту довелося запам’ятати, що він зберігав у колекції.
У дженериках, де винайдено, щоб обійти це обмеження, розробник оголосив би збережений тип один раз, а компілятор зробив би це замість цього.

List<String> aNumberList = new ArrayList<String>();
aNumberList.add("one");
Integer iOne = aNumberList.get(0);//Compile time error
String sOne = aNumberList.get(0);//works fine

Для порівняння:

// Old style collections now known as raw types
List aList = new ArrayList(); //Could contain anything
// New style collections with Generics
List<String> aList = new ArrayList<String>(); //Contains only Strings

Більш складний порівняльний інтерфейс:

//raw, not type save can compare with Other classes
class MyCompareAble implements CompareAble
{
   int id;
   public int compareTo(Object other)
   {return this.id - ((MyCompareAble)other).id;}
}
//Generic
class MyCompareAble implements CompareAble<MyCompareAble>
{
   int id;
   public int compareTo(MyCompareAble other)
   {return this.id - other.id;}
}

Зауважте, що неможливо реалізувати CompareAbleінтерфейс compareTo(MyCompareAble)із типовими компонентами. Чому не слід їх використовувати:

  • Будь-яке Objectзбережене у файлі Collectionмає бути передано перед тим, як його можна використовувати
  • Використання дженерики дозволяє перевіряти час компіляції
  • Використання необроблених типів - це те саме, що зберігання кожного значення Object

Що робить компілятор: Generics є зворотною сумісністю, вони використовують ті ж класи Java, що і сировинні типи. Магія трапляється здебільшого під час компіляції.

List<String> someStrings = new ArrayList<String>();
someStrings.add("one");
String one = someStrings.get(0);

Складається як:

List someStrings = new ArrayList();
someStrings.add("one"); 
String one = (String)someStrings.get(0);

Це той самий код, який ви б написали, якби безпосередньо використовували вихідні типи. Думав, що я не впевнений, що відбувається з CompareAbleінтерфейсом, я думаю, що він створює дві compareToфункції, одна з яких - aMyCompareAble а друга приймає Objectта передає її першій після того, як її буде передано.

Які альтернативи сировинним типам: Використовуйте дженерики


30

Сирий тип - це назва загального класу чи інтерфейсу без аргументів типу. Наприклад, враховуючи загальний клас Box:

public class Box<T> {
    public void set(T t) { /* ... */ }
    // ...
}

Щоб створити параметризований тип Box<T>, ви надаєте фактичний аргумент типу для параметра формального типу T:

Box<Integer> intBox = new Box<>();

Якщо аргумент фактичного типу пропущено, ви створюєте необроблений тип Box<T>:

Box rawBox = new Box();

Тому Boxє сировинним типом родового типуBox<T> . Однак некласовий клас або тип інтерфейсу не є необробленим типом.

Сировинні типи відображаються в застарілому коді, оскільки багато класів API (наприклад, класи Collections) не були загальними до JDK 5.0. Використовуючи необроблені типи, ви по суті отримуєте поведінку перед генериками - це Boxдає вам Objects. Для зворотної сумісності дозволяється присвоювати параметризований тип його сировинному типу:

Box<String> stringBox = new Box<>();
Box rawBox = stringBox;               // OK

Але якщо призначити сировинний тип параметризованому типу, ви отримаєте попередження:

Box rawBox = new Box();           // rawBox is a raw type of Box<T>
Box<Integer> intBox = rawBox;     // warning: unchecked conversion

Ви також отримуєте попередження, якщо використовуєте необроблений тип для виклику загальних методів, визначених у відповідному загальному типі:

Box<String> stringBox = new Box<>();
Box rawBox = stringBox;
rawBox.set(8);  // warning: unchecked invocation to set(T)

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

У розділі Type Erasure є додаткова інформація про те, як компілятор Java використовує необроблені типи.

Повідомлення про помилки без перевірки

Як згадувалося раніше, при змішуванні застарілого коду з загальним кодом, ви можете зіткнутися з попереджувальними повідомленнями, подібними до таких:

Примітка: Example.java використовує неперевірені або небезпечні операції.

Примітка. Перекомпілюйте з -Xlint: не встановлено прапорці для деталей.

Це може статися при використанні більш старого API, який працює на вихідних типах, як показано в наступному прикладі:

public class WarningDemo {
    public static void main(String[] args){
        Box<Integer> bi;
        bi = createBox();
    }

    static Box createBox(){
        return new Box();
    }
}

Термін "неперевірений" означає, що у компілятора недостатньо інформації про тип для виконання всіх перевірок типів, необхідних для забезпечення безпеки типу. Попередження "не перевірено" вимкнено за замовчуванням, хоча компілятор дає підказку. Щоб побачити всі "неперевірені" попередження, перекомпілюйте з -Xlint: невірно.

Перекомпіляція попереднього прикладу за допомогою -Xlint: без галочки виявляється наступна додаткова інформація:

WarningDemo.java:4: warning: [unchecked] unchecked conversion
found   : Box
required: Box<java.lang.Integer>
        bi = createBox();
                      ^
1 warning

Щоб повністю вимкнути неперевірені попередження, використовуйте прапорець -Xlint: -контрольований. @SuppressWarnings("unchecked")Анотацію пригнічує неперевірені попередження. Якщо ви не знайомі з@SuppressWarnings синтаксисом, див. Анотації.

Оригінальне джерело: Підручники Java


21

"Сирий" тип на Java - це клас, який не є загальним і має справу з "необробленими" Об'єктами, а не безпечними для типу параметрами загального типу.

Наприклад, перш ніж доступні дженерики Java, ви б використовували такий клас колекції:

LinkedList list = new LinkedList();
list.add(new MyObject());
MyObject myObject = (MyObject)list.get(0);

Коли ви додаєте свій об'єкт до списку, це не має значення для якого типу об'єкта він є, і коли ви отримуєте його зі списку, ви повинні чітко віддати його до типу, який ви очікуєте.

Використовуючи дженерики, ви видаляєте фактор "невідомий", оскільки ви повинні чітко вказати, який тип об'єктів може перейти до списку:

LinkedList<MyObject> list = new LinkedList<MyObject>();
list.add(new MyObject());
MyObject myObject = list.get(0);

Зауважте, що за допомогою дженерики вам не потрібно викидати об'єкт, що надходить з виклику get, колекція заздалегідь визначена для роботи лише з MyObject. Саме цей факт є головним рушійним фактором для генериків. Це змінює джерело помилок виконання на щось, що можна перевірити під час компіляції.


3
Більш конкретно, необроблений тип - це те, що ви отримуєте, коли просто опускаєте параметри типу для загального типу. Сирі типи справді були лише функцією зворотної сумісності, і вони потенційно можуть бути видалені. Ви можете отримати подібну поведінку, використовуючи? параметри підстановки.
Джон Плоскість

@zerocrates: схожі, але різні! Використання ?все ще пропонує тип безпеки. Я висвітлював це у своїй відповіді.
полігенмастильні матеріали

19
 private static List<String> list = new ArrayList<String>();

Вам слід вказати тип-параметр.

Попередження радить, що типи, визначені для підтримки generic, повинні бути параметризовані, а не використовувати їх необроблену форму.

Listвизначається підтримки дженериків: public class List<E>. Це дозволяє безліч безпечних операцій, які перевіряються під час компіляції.


3
Тепер замінено алмазним висновком на Java 7 -private static List<String> list = new ArrayList<>();
Іен Кемпбелл

14

Що таке сировина, і чому я часто чую, що їх не слід використовувати в новому коді?

"Сирий тип" - це використання загального класу без вказівки аргументів типу для його параметризованих типів, наприклад, Listзамість використання List<String>. Коли вводили дженерики в Java, було оновлено кілька класів для використання дженериків. Використання цих класів як "необробленого типу" (без вказівки аргументу типу) дозволило застарілому коду все-таки компілювати.

"Сирі типи" використовуються для зворотної сумісності. Їх використання в новому коді не рекомендується, оскільки використання загального класу з аргументом типу дозволяє посилити введення тексту, що, в свою чергу, може покращити зрозумілість коду та призвести до попереднього пошуку потенційних проблем.

Яка альтернатива, якщо ми не можемо використовувати сировинні типи, і як це краще?

Кращою альтернативою є використання загальних класів за призначенням - з відповідним аргументом типу (наприклад, List<String> ). Це дозволяє програмісту конкретизувати типи, передає більше значення майбутнім обслуговуючим особам щодо передбачуваного використання змінної або структури даних, а також дозволяє компілятору забезпечити кращу безпеку типу. Ці переваги разом можуть покращити якість коду та запобігти введенню деяких помилок кодування.

Наприклад, для методу, коли програміст хоче забезпечити змінну списку під назвою "імена", містить лише рядки:

List<String> names = new ArrayList<String>();
names.add("John");          // OK
names.add(new Integer(1));  // compile error

1
Ах, настільки спокусився скопіювати polygenelubricantsпосилання "необробленого типу" із stackoverflow.com/questions/2770111/… у свою власну відповідь, але я вважаю, що залишу їх для використання у власній відповіді.
Берт F

1
так, я по суті копіював і вставляв цей сегмент скрізь, де люди використовують старі типи в stackoverflow, і, нарешті, вирішив просто мати одне питання, на яке слід звертатися. Я сподіваюся, що це хороший внесок для громади.
полігенмастильні матеріали

1
@polygenelubricants Я помітив - ми потрапили на ті самі запитання :-)
Bert F

1
@ ha9u63ar: Дійсно. Загалом, стислі та прості відповіді принаймні такі ж хороші, як і довгі та прийняті.
displayName

Що "сильніший сипінг"?
carloswm85

12

Компілятор хоче, щоб ви написали це:

private static List<String> list = new ArrayList<String>();

бо в іншому випадку ви можете додати будь-який тип, який вам подобається list, зробивши цю інстанцію new ArrayList<String>()безглуздою. Java-дженерики - це лише функція часу компіляції, тому об’єкт, створений за допомогою, new ArrayList<String>()буде радісно приймати Integerабо JFrameелементи, якщо йому присвоєно посилання "необробленого типу" List- сам об'єкт нічого не знає про те, які типи він повинен містити, лише компілятор.


12

Тут я розглядаю кілька випадків, за допомогою яких можна прояснити концепцію

1. ArrayList<String> arr = new ArrayList<String>();
2. ArrayList<String> arr = new ArrayList();
3. ArrayList arr = new ArrayList<String>();

Випадок 1

ArrayList<String> arrце ArrayListпосилальна змінна з типом, на Stringяку посилається ArralyListоб'єкт типу String. Це означає, що він може містити лише об'єкт типу String.

Це суворий, а Stringне сирий тип, тому він ніколи не підніме попередження.

    arr.add("hello");// alone statement will compile successfully and no warning.

    arr.add(23);  //prone to compile time error.
     //error: no suitable method found for add(int)

Випадок 2

У цьому випадку ArrayList<String> arrце суворий тип, але ваш Об'єкт new ArrayList();є необробленим.

    arr.add("hello"); //alone this compile but raise the warning.
    arr.add(23);  //again prone to compile time error.
    //error: no suitable method found for add(int)

тут arrстрогий тип. Отже, це додасть помилку часу компіляції при додаванні integer.

Попередження : - RawОб'єкт типу посилається на Strictтип змінної змінної ArrayList.

Випадок 3

У цьому випадку ArrayList arrце необроблений тип, але ваш об'єкт new ArrayList<String>();- строгий тип.

    arr.add("hello");  
    arr.add(23);  //compiles fine but raise the warning.

Він додасть до нього будь-який тип Об'єкту, оскільки arrце Сирий тип.

Попередження : - StrictОб'єкт rawтипу посилається на тип змінної змінної.


8

Сировини типу є відсутність в параметрі типу при використанні універсального типу.

Сировина типу не слід використовувати , оскільки це може привести до помилок у час виконання, як і вставки doubleв те , що повинно було бути Setв intс.

Set set = new HashSet();
set.add(3.45); //ok

Отримуючи речі з програми Set, ви не знаєте, що виходить. Припустимо, що ви очікуєте, що це все буде int, ви кидаєте це Integer; виняток під час виконання, колиdouble йде 3.45.

Якщо параметр типу доданий до вашого Set, ви отримаєте помилку компіляції відразу. Ця попередня помилка дозволяє вирішити проблему, перш ніж щось підірветься під час виконання (таким чином заощаджуючи час та зусилля).

Set<Integer> set = new HashSet<Integer>();
set.add(3.45); //NOT ok.

7

Ось ще один випадок, коли сирі типи будуть кусати вас:

public class StrangeClass<T> {
  @SuppressWarnings("unchecked")
  public <X> X getSomethingElse() {
    return (X)"Testing something else!";
  }

  public static void main(String[] args) {
    final StrangeClass<String> withGeneric    = new StrangeClass<>();
    final StrangeClass         withoutGeneric = new StrangeClass();
    final String               value1,
                               value2;

    // Compiles
    value1 = withGeneric.getSomethingElse();

    // Produces compile error:
    // incompatible types: java.lang.Object cannot be converted to java.lang.String
    value2 = withoutGeneric.getSomethingElse();
  }
}

Як було сказано у прийнятій відповіді, ви втрачаєте будь-яку підтримку для дженериків у коді необробленого типу. Кожен параметр типу перетворюється на його стирання (що у наведеному вище прикладі справедливо Object).


5

Що говорить, що ваш listєList визначені об'єкти. Тобто Java не знає, які об’єкти знаходяться всередині списку. Тоді, коли ви хочете повторити список, вам потрібно передати кожен елемент, щоб мати доступ до властивостей цього елемента (у цьому випадку String).

Загалом, краща ідея параметризувати колекції, тому у вас не виникнуть проблеми з перетворенням, ви зможете лише додати елементи параметризованого типу, і ваш редактор запропонує вам вибрати відповідні методи.

private static List<String> list = new ArrayList<String>();

4

сторінка підручника .

Сирий тип - це назва загального класу чи інтерфейсу без аргументів типу. Наприклад, враховуючи загальний клас Box:

public class Box<T> {
    public void set(T t) { /* ... */ }
    // ...
}

Щоб створити параметризований тип Box, ви подаєте аргумент фактичного типу для формального параметра типу T:

Box<Integer> intBox = new Box<>();

Якщо аргумент фактичного типу пропущено, ви створюєте необроблений тип поля:

Box rawBox = new Box();

2

Уникайте сирих видів

Сирі типи відносяться до використання загального типу, не вказуючи параметр типу.

Наприклад ,

Список - це вихідний тип, поки List<String> параметризований тип.

Коли дженерики були введені в JDK 1.5, вихідні типи зберігалися лише для підтримки зворотної сумісності зі старими версіями Java. Хоча використання сировинних типів все ще можливо,

Їх слід уникати :

  • Зазвичай вони вимагають кастингу
  • Вони не є безпечними, а деякі важливі помилки з’являться лише під час виконання
  • Вони менш виразні і не самодокументують так само, як параметризовані типи Приклад

    import java.util.*;
    
    public final class AvoidRawTypes {
    
    void withRawType() {
    
        //Raw List doesn't self-document, 
        //doesn't state explicitly what it can contain
    
        List stars = Arrays.asList("Arcturus", "Vega", "Altair");
    
        Iterator iter = stars.iterator();
    
        while (iter.hasNext()) {
    
            String star = (String) iter.next(); //cast needed
    
            log(star);
        }
    
    }
    
    void withParameterizedType() {
    
        List < String > stars = Arrays.asList("Spica", "Regulus", "Antares");
    
        for (String star: stars) {
    
            log(star);
        }
    
    }
    
    private void log(Object message) {
    
        System.out.println(Objects.toString(message));
    
    }
    
    }

Довідково : https://docs.oracle.com/javase/tutorial/java/generics/rawTypes.html


1

Я знайшов цю сторінку, зробивши кілька зразків вправ і маючи таку саму загадку.

============== Я пішов з цього коду, як надає зразок ================

public static void main(String[] args) throws IOException {

    Map wordMap = new HashMap();
    if (args.length > 0) {
        for (int i = 0; i < args.length; i++) {
            countWord(wordMap, args[i]);
        }
    } else {
        getWordFrequency(System.in, wordMap);
    }
    for (Iterator i = wordMap.entrySet().iterator(); i.hasNext();) {
        Map.Entry entry = (Map.Entry) i.next();
        System.out.println(entry.getKey() + " :\t" + entry.getValue());
    }

====================== До цього коду =========================

public static void main(String[] args) throws IOException {
    // replace with TreeMap to get them sorted by name
    Map<String, Integer> wordMap = new HashMap<String, Integer>();
    if (args.length > 0) {
        for (int i = 0; i < args.length; i++) {
            countWord(wordMap, args[i]);
        }
    } else {
        getWordFrequency(System.in, wordMap);
    }
    for (Iterator<Entry<String, Integer>> i = wordMap.entrySet().iterator(); i.hasNext();) {
        Entry<String, Integer> entry =   i.next();
        System.out.println(entry.getKey() + " :\t" + entry.getValue());
    }

}

===================================================== ==============================

Це може бути безпечнішим, але для того, щоб занепокоїти філософію, знадобилося 4 години ...


0

Сирі типи добре, коли вони виражають те, що ви хочете висловити.

Наприклад, функція десеріалізації може повернути a List, але вона не знає тип елемента списку. Тож Listвідповідний тип повернення тут.


Ви можете використовувати? як параметр типу
Даніель Кіс

Так, але це більше набирати, і я проти набору більше. :)
Стефан Рейх
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.