Co to jest typ surowy i dlaczego nie powinniśmy go używać?

662

Pytania:

  • Jakie są typy raw w Javie i dlaczego często słyszę, że nie powinny być używane w nowym kodzie?
  • Jaka jest alternatywa, jeśli nie możemy używać typów surowych i jak jest lepsza?
środki smarujące wielotlenowe
źródło
samouczki Java nadal używają JComboBox, który powoduje to ostrzeżenie. Która wersja combobox nie spowoduje tego ostrzeżenia? docs.oracle.com/javase/tutorial/uiswing/components/…
SuperStar
1
Zauważ, że powodem istnienia typów surowych jest kompatybilność wsteczna z Javą 1.4 i starszymi wersjami, która w ogóle nie miała generics.
Jesper

Odpowiedzi:

744

Co to jest typ surowy?

Specyfikacja języka Java definiuje typ surowy w następujący sposób:

JLS 4.8 Rodzaje surowców

Typ surowy jest zdefiniowany jako jeden z:

  • Typ odwołania, który jest tworzony przez przyjęcie nazwy ogólnej deklaracji typu bez towarzyszącej listy argumentów typu.

  • Typ tablicy, której typ elementu jest typem surowym.

  • Typ nienależący do statictypu surowego, Rktóry nie jest dziedziczony z nadklasy lub superinterfejsu R.

Oto przykład ilustrujący:

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!)
    }
}

Tutaj MyType<E>jest typ sparametryzowany ( JLS 4.5 ). Zwykle potocznie określa się ten typ jako po prostu MyTypew skrócie, ale technicznie nazwa to MyType<E>.

mtma typ raw (i generuje ostrzeżenie o kompilacji) na podstawie pierwszego punktu w powyższej definicji; innma również typ surowy według trzeciego punktu.

MyType.Nestednie jest sparametryzowanym typem, nawet jeśli jest to typ członka sparametryzowanego typu MyType<E>, ponieważ jest static.

mt1, i mt2oba są zadeklarowane za pomocą rzeczywistych parametrów typu, więc nie są to typy surowe.


Co jest takiego specjalnego w typach surowych?

Zasadniczo typy surowe zachowują się tak, jak przed wprowadzeniem leków generycznych. Oznacza to, że w czasie kompilacji poniższe informacje są całkowicie legalne.

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

Powyższy kod działa dobrze, ale załóżmy, że masz również:

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

Teraz napotykamy problemy w czasie wykonywania, ponieważ nameszawiera coś, co nie jest instanceof String.

Można przypuszczać, że jeśli chcesz, namesaby zawierał tylko String, to mógłby być może nadal korzystać typ surowca i ręcznie sprawdzić każdy add samodzielnie, a następnie ręcznie odlewane do Stringkażdego elementu z names. Jeszcze lepiej , chociaż NIE należy używać surowego typu i pozwolić kompilatorowi wykonać całą pracę za Ciebie , wykorzystując moc generycznych programów Java.

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

Oczywiście, jeśli NIE chcesz names, aby umożliwić Boolean, po czym można je zadeklarować jak List<Object> namesi powyższy kod będzie kompilować.

Zobacz też


Czym różni się typ raw od używania <Object>jako parametrów typu?

Oto cytat z Effective Java 2nd Edition, pozycja 23: Nie używaj surowych typów w nowym kodzie :

Jaka jest różnica między typem surowym Lista typem sparametryzowanym List<Object>? Mówiąc luźniej, ten pierwszy zrezygnował z ogólnego sprawdzania typów, podczas gdy ten drugi wyraźnie powiedział kompilatorowi, że jest w stanie pomieścić obiekty dowolnego typu. Chociaż można przekazać a List<String>do parametru typu List, nie można go przekazać do parametru typu List<Object>. Istnieją reguły podtypów dla rodzajów ogólnych i List<String>jest to podtyp typu surowego List, ale nie typu sparametryzowanego List<Object>. W rezultacie tracisz bezpieczeństwo typu, jeśli używasz typu surowego List, ale nie, jeśli używasz typu sparametryzowanegoList<Object> .

Aby zilustrować tę kwestię, rozważ następującą metodę, która bierze List<Object>a dodaje a new Object().

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

Ogólne w Javie są niezmienne. A List<String>nie jest a List<Object>, więc poniższe wygeneruje ostrzeżenie kompilatora:

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

Gdybyś zadeklarował, appendNewObjectże Listjako parametr użyjesz surowego typu , to się skompiluje, a zatem stracisz bezpieczeństwo typu, które otrzymujesz od generycznych.

Zobacz też


Czym różni się typ raw od używania <?>jako parametru typu?

List<Object>, List<String>itd. są wszystkie List<?>, więc kuszące może być stwierdzenie, że są po prostu List. Jest jednak zasadnicza różnica: ponieważ List<E>tylko definicja add(E), nie można dodać dowolnego obiektu do List<?>. Z drugiej strony, ponieważ typ surowy Listnie ma bezpieczeństwa typu, możesz zrobić addprawie wszystko List.

Rozważ następującą odmianę poprzedniego fragmentu:

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

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

Kompilator wykonał wspaniałą pracę, chroniąc cię przed potencjalnym naruszeniem niezmienności typu List<?>! Jeśli zadeklarujesz parametr jako typ surowy List list, kod skompiluje się i naruszysz niezmiennik typu List<String> names.


Surowy typ to kasowanie tego typu

Powrót do JLS 4.8:

Możliwe jest użycie jako typu skasowania sparametryzowanego typu lub skasowania typu tablicowego, którego typem elementu jest sparametryzowany typ. Taki typ nazywany jest typem surowym .

[...]

Nadklasy (odpowiednio superinterfaces) typu surowego są wymazaniami nadklas (superinterfaces) dowolnej parametryzacji typu ogólnego.

Typ konstruktora, metoda instancji lub niepola statictypu surowego, Cktóry nie jest dziedziczony z jego nadklas lub superinterfejsów, jest typem surowym, który odpowiada usunięciu jego typu w ogólnej deklaracji odpowiadającej C.

Mówiąc prościej, gdy używany jest typ surowy, konstruktory, metody instancji i niepole staticrównież usuwane .

Weź następujący przykład:

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);
    }
}

Kiedy używamy surowego MyType, getNameszostaje również wymazany, dzięki czemu zwraca surowe List!

JLS 4.6 nadal wyjaśnia, co następuje:

Usuwanie typu mapuje również sygnaturę konstruktora lub metody na sygnaturę, która nie ma sparametryzowanych typów ani zmiennych typów. Kasowanie sygnatury konstruktora lub metody sjest sygnaturą składającą się z tej samej nazwy si kasowania wszystkich formalnych typów parametrów podanych w s.

Typ zwracany przez metodę i parametry typu ogólnej metody lub konstruktora również są usuwane, jeśli metoda lub podpis konstruktora zostaną usunięte.

Usunięcie podpisu metody ogólnej nie ma parametrów typu.

Poniższy raport o błędach zawiera przemyślenia Maurizio Cimadamore, twórcy kompilatora i Alexa Buckley'a, jednego z autorów JLS, na temat tego, dlaczego takie zachowanie powinno nastąpić: https://bugs.openjdk.java.net/browse / JDK-6400189 . (Krótko mówiąc, upraszcza to specyfikację).


Jeśli jest to niebezpieczne, dlaczego można używać surowego typu?

Oto kolejny cytat z JLS 4.8:

Użycie typów surowych jest dozwolone tylko jako ustępstwo do zgodności ze starszym kodem. Użycie typów surowych w kodzie napisanym po wprowadzeniu generyczności do języka programowania Java jest zdecydowanie odradzane. Możliwe, że przyszłe wersje języka programowania Java nie zezwalają na stosowanie typów surowych.

Efektywna Java 2. edycja ma również tę opcję:

Biorąc pod uwagę, że nie powinieneś używać typów surowych, dlaczego projektanci języków na to zezwolili? Aby zapewnić zgodność.

Platforma Java miała wkroczyć w drugą dekadę, kiedy wprowadzono generyczne, i istniała ogromna ilość kodu Java, który nie korzystał z generycznych. Uznano za krytyczne, że cały ten kod pozostaje legalny i interoperacyjny z nowym kodem, który używa generycznych. Musi być legalne przekazywanie wystąpień sparametryzowanych typów do metod zaprojektowanych do użycia ze zwykłymi typami i odwrotnie. Ten wymóg, znany jako kompatybilność migracji , podjął decyzję o wsparciu typów surowych.

Podsumowując, typy surowe NIGDY nie powinny być używane w nowym kodzie. Zawsze powinieneś używać sparametryzowanych typów .


Czy nie ma wyjątków?

Niestety, ponieważ generyczne Java nie są weryfikowane, istnieją dwa wyjątki, w których typy surowe muszą być użyte w nowym kodzie:

  • Literały klasowe, np. List.classNieList<String>.class
  • instanceofoperand, np. o instanceof Setnieo instanceof Set<String>

Zobacz też

środki smarujące wielotlenowe
źródło
16
Co masz na myśli, mówiąc, że „generyczne elementy Java są niezrefikowane”?
Carl G,
7
W przypadku drugiego wyjątku składnia o instanceof Set<?>jest również dozwolona w celu uniknięcia typu surowego (choć w tym przypadku jest to tylko powierzchowne).
Paul Bellora,
1
Typy surowe są bardzo przydatne i zmniejszają kod bojlera w przypadku wyszukiwania JNDI dla komponentu bean, który rozszerza interfejs. To rozwiązuje potrzebę pisania nzdalnych komponentów bean dla każdej klasy implementującej z identycznym kodem.
djmj
8
„Niezrefikowany” to kolejny sposób na stwierdzenie, że zostały usunięte. Kompilator wie, jakie są parametry ogólne, ale informacje te nie są przekazywane do wygenerowanego kodu bajtowego. JLS wymaga, aby literały klas nie miały parametrów typu.
Erick G. Hagstrom,
2
@OldCurmudgeon To ciekawe. Mam na myśli, że oficjalnie tak nie jest , ponieważ literał klasy zdefiniowany jako just TypeName.class, gdzie TypeNamejest zwykły identyfikator ( jls ). Mówiąc hipotetycznie, myślę, że tak może być. Być może jako wskazówka List<String>.classjest wariant, który JLS nazywa konkretnie błędem kompilatora, więc jeśli kiedykolwiek dodadzą go do języka, spodziewam się, że to ten, którego używają.
Radiodef
62

Jakie są typy raw w Javie i dlaczego często słyszę, że nie powinny być używane w nowym kodzie?

Surowe typy to starożytna historia języka Java. Na początku były Collectionsi nie posiadały Objectsnic więcej i nic mniej. Każda operacja na Collectionswymaganych rzutach od Objectdo pożądanego typu.

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

Chociaż działało to przez większość czasu, błędy się zdarzały

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

Stare beztypowe kolekcje nie mogły wymuszać bezpieczeństwa typu, więc programista musiał pamiętać, co przechował w kolekcji.
Gdy opracowano ogólne, aby obejść to ograniczenie, programista zadeklaruje typ przechowywany jeden raz, a kompilator zrobi to zamiast tego.

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

Dla porownania:

// 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

Bardziej złożony interfejs porównywalny:

//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;}
}

Zauważ, że nie można zaimplementować CompareAbleinterfejsu z compareTo(MyCompareAble)typami raw. Dlaczego nie powinieneś ich używać:

  • Wszelkie Objectprzechowywane w a Collectionmuszą zostać oddane przed użyciem
  • Korzystanie ze składników ogólnych umożliwia sprawdzanie czasu kompilacji
  • Używanie typów raw jest takie samo jak przechowywanie każdej wartości jako Object

Co robi kompilator: Generics są wstecznie kompatybilne, używają tych samych klas java co surowe typy. Magia dzieje się głównie w czasie kompilacji.

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

Zostanie skompilowany jako:

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

Jest to ten sam kod, który napisałbyś, gdybyś używał typów surowych bezpośrednio. Pomyślałem, że nie jestem pewien, co dzieje się z CompareAbleinterfejsem, myślę, że tworzy on dwie compareTofunkcje, jedna bierze MyCompareAblea druga bierze Objecti przekazuje do pierwszej po rzuceniu.

Jakie są alternatywy dla typów surowych: Użyj generycznych

josefx
źródło
30

Typ surowy to nazwa ogólnej klasy lub interfejsu bez żadnych argumentów typu. Na przykład biorąc pod uwagę ogólną klasę Box:

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

Aby utworzyć sparametryzowany typ Box<T>, podajesz argument typu rzeczywistego dla formalnego parametru typu T:

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

Jeśli argument typu rzeczywistego zostanie pominięty, tworzony jest surowy typ Box<T>:

Box rawBox = new Box();

Dlatego Boxjest typem surowym typu ogólnego Box<T>. Jednak nie ogólna klasa lub typ interfejsu nie jest typem surowym.

Typy surowe pojawiają się w starszym kodzie, ponieważ wiele klas API (takich jak klasy Kolekcje) nie było ogólnych przed JDK 5.0. Używając typów surowych, zasadniczo uzyskujesz zachowanie przedgeneryczne - a Boxdaje ci Objects. W celu zachowania zgodności wstecznej dozwolone jest przypisywanie sparametryzowanego typu do jego typu surowego:

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

Ale jeśli przypiszesz typ surowy do sparametryzowanego typu, pojawi się ostrzeżenie:

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

Pojawia się również ostrzeżenie, jeśli używasz typu raw do wywoływania metod ogólnych zdefiniowanych w odpowiednim typie ogólnym:

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

Ostrzeżenie pokazuje, że typy surowe omijają ogólne sprawdzanie typów, odraczając przechwytywanie niebezpiecznego kodu do środowiska wykonawczego. Dlatego należy unikać używania typów surowych.

Sekcja Usuwanie typu zawiera więcej informacji o tym, w jaki sposób kompilator Java wykorzystuje typy surowe.

Niesprawdzone komunikaty o błędach

Jak wspomniano wcześniej, podczas mieszania starszego kodu z kodem ogólnym mogą pojawić się komunikaty ostrzegawcze podobne do następujących:

Uwaga: Example.java używa niesprawdzonych lub niebezpiecznych operacji.

Uwaga: Ponowna kompilacja z opcją -Xlint: niezaznaczone dla szczegółów.

Może się to zdarzyć przy użyciu starszego interfejsu API działającego na typach raw, jak pokazano w poniższym przykładzie:

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

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

Termin „niezaznaczony” oznacza, że ​​kompilator nie ma wystarczających informacji o typie, aby wykonać wszystkie kontrole typu niezbędne do zapewnienia bezpieczeństwa typu. Ostrzeżenie „niezaznaczone” jest domyślnie wyłączone, choć kompilator daje podpowiedź. Aby zobaczyć wszystkie „niezaznaczone” ostrzeżenia, ponownie skompiluj z opcją -Xlint: niezaznaczone.

Ponowna kompilacja poprzedniego przykładu z opcją -Xlint: niezaznaczone ujawnia następujące dodatkowe informacje:

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

Aby całkowicie wyłączyć niesprawdzone ostrzeżenia, użyj flagi -Xlint: -unchecked. @SuppressWarnings("unchecked")Adnotacja tłumi niezaznaczone ostrzeżenia. Jeśli nie znasz @SuppressWarningsskładni, zobacz Adnotacje.

Oryginalne źródło: Poradniki Java

Adelina
źródło
21

„Surowy” typ w Javie to klasa, która nie jest ogólna i zajmuje się „surowymi” obiektami, a nie bezpiecznymi dla typu parametrami typu ogólnego.

Na przykład przed udostępnieniem ogólnych składników Java należy użyć klasy kolekcji takiej jak ta:

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

Kiedy dodajesz swój obiekt do listy, nie ma znaczenia, jaki to jest typ obiektu, a kiedy pobierzesz go z listy, musisz jawnie rzutować go na oczekiwany typ.

Używając ogólnych, usuwasz czynnik „nieznany”, ponieważ musisz jawnie określić, jaki typ obiektów może znaleźć się na liście:

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

Zauważ, że w przypadku ogólnych nie musisz rzutować obiektu pochodzącego z wywołania get, kolekcja jest wstępnie zdefiniowana do pracy tylko z MyObject. Ten fakt jest głównym czynnikiem napędzającym leki generyczne. Zmienia źródło błędów w czasie wykonywania na coś, co można sprawdzić podczas kompilacji.

Andy White
źródło
3
Mówiąc dokładniej, typ surowy jest tym, co otrzymuje się po prostu pomijając parametry typu dla typu ogólnego. Typy raw były zawsze tylko funkcją zgodności wstecznej i potencjalnie mogą zostać usunięte. Możesz uzyskać podobne zachowanie za pomocą? parametry wieloznaczne.
John Flatness,
@zerocrates: podobny, ale inny! Używanie ?nadal zapewnia bezpieczeństwo typu. Omówiłem to w swojej odpowiedzi.
polygenelrycyny
19
 private static List<String> list = new ArrayList<String>();

Powinieneś określić parametr typu.

Ostrzeżenie informuje, że typy zdefiniowane do obsługi rodzajów ogólnych powinny zostać sparametryzowane, a nie przy użyciu ich surowej postaci.

Listjest zdefiniowana generycznych wsparcia: public class List<E>. Pozwala to na wiele bezpiecznych operacji, które są sprawdzane podczas kompilacji.

Bozho
źródło
3
Teraz zastąpione wnioskami diamentowymi w Javie 7private static List<String> list = new ArrayList<>();
Ian Campbell
14

Co to jest typ raw i dlaczego często słyszę, że nie należy ich używać w nowym kodzie?

„Typ surowy” to użycie klasy ogólnej bez określania argumentów typu dla sparametryzowanych typów, np. Użycie Listzamiast List<String>. Kiedy w Javie wprowadzono leki generyczne, zaktualizowano kilka klas, aby korzystały z nich. Użycie tych klas jako „typu surowego” (bez podania argumentu typu) pozwoliło na kompilację starszego kodu.

„Typy surowe” są używane dla kompatybilności wstecznej. Ich użycie w nowym kodzie nie jest zalecane, ponieważ użycie klasy ogólnej z argumentem typu pozwala na silniejsze pisanie, co z kolei może poprawić zrozumiałość kodu i prowadzić do wcześniejszego wychwytywania potencjalnych problemów.

Jaka jest alternatywa, jeśli nie możemy używać typów surowych i jak jest lepsza?

Preferowaną alternatywą jest użycie klas ogólnych zgodnie z przeznaczeniem - z argumentem odpowiedniego typu (np List<String>.). Pozwala to programiście na bardziej precyzyjne określenie typów, przekazuje przyszłym opiekunom więcej znaczenia na temat zamierzonego zastosowania zmiennej lub struktury danych, a także pozwala kompilatorowi wymusić lepsze bezpieczeństwo typu. Te zalety łącznie mogą poprawić jakość kodu i pomóc zapobiec wprowadzeniu niektórych błędów kodowania.

Na przykład dla metody, w której programista chce się upewnić, że zmienna List o nazwie „names” zawiera tylko ciągi znaków:

List<String> names = new ArrayList<String>();
names.add("John");          // OK
names.add(new Integer(1));  // compile error
Bert F.
źródło
1
Ach, więc kusiło mnie, aby skopiować polygenelubricants„surowe” referencje z stackoverflow.com/questions/2770111/... do mojej własnej odpowiedzi, ale przypuszczam, że zostawię je do użycia we własnej odpowiedzi.
Bert F
1
tak, w zasadzie kopiowałem i wklejałem ten segment wszędzie, gdzie ludzie używają typów raw przy przepełnieniu stosu, i w końcu zdecydowałem się od razu odpowiedzieć na jedno pytanie. Mam nadzieję, że to dobry wkład dla społeczności.
polygenelrycyny
1
@polygenelubricants Zauważyłem - trafiliśmy na te same pytania :-)
Bert F
1
@ ha9u63ar: Rzeczywiście. Ogólnie rzecz biorąc, zwięzłe i proste odpowiedzi są co najmniej tak dobre, jak te długie i akceptowane.
displayName
Co to jest „mocniejsze odsysanie”?
carloswm85,
12

Kompilator chce, abyś napisał:

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

ponieważ w przeciwnym razie możesz dodać dowolny typ list, co sprawia, że ​​tworzenie instancji jest new ArrayList<String>()bezcelowe. Generyczne elementy języka Java są tylko funkcją czasu kompilacji, więc obiekt utworzony za pomocą new ArrayList<String>()tego elementu chętnie zaakceptuje elementy Integerlub JFrameelementy, jeśli zostaną przypisane do odwołania do „typu surowego” List- sam obiekt nie wie nic o typach, które powinien zawierać, tylko kompilator.

Michael Borgwardt
źródło
12

Rozważam wiele przypadków, w których można wyjaśnić tę koncepcję

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

Przypadek 1

ArrayList<String> arrjest to ArrayListzmienna referencyjna z typem, Stringktóra odnosi się do ArralyListobiektu typu String. Oznacza to, że może przechowywać tylko obiekt typu String.

Nie jest Stringtypem surowym, więc nigdy nie wywoła ostrzeżenia.

    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)

Przypadek 2

W tym przypadku ArrayList<String> arrjest to typ ścisły, ale Twój obiekt new ArrayList();jest typem surowym.

    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)

tutaj arrjest typ ścisły. Tak więc podniesie błąd czasu kompilacji podczas dodawania integer.

Ostrzeżenie : - RawObiekt typu odwołuje się do Stricttypu Zmienna referencyjna typu ArrayList.

Przypadek 3

W tym przypadku ArrayList arrjest to typ surowy, ale twój obiekt new ArrayList<String>();jest typem ścisłym.

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

Doda do niego dowolny typ obiektu, ponieważ arrjest to typ surowy.

Ostrzeżenie : - StrictObiekt typu odwołuje się do rawtypu Zmienna.

Vikrant Kashyap
źródło
8

Typ surowy to brak parametru typu, gdy używany jest typ ogólny.

Raw typu nie powinny być stosowane, ponieważ może to spowodować błędy wykonawcze, jak wstawiając doublew to, co miało być Setod ints.

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

Podczas odzyskiwania rzeczy z Set, nie wiesz, co wychodzi. Załóżmy, że oczekujesz, że to będzie wszystko int, do czego rzucasz Integer; wyjątek w czasie wykonywania, gdy doublepojawi się wersja 3.45.

Po dodaniu do parametru parametru typuSet od razu pojawi się błąd kompilacji. Ten zapobiegawczy błąd pozwala naprawić problem, zanim coś wybuchnie podczas działania (oszczędzając w ten sposób czas i wysiłek).

Set<Integer> set = new HashSet<Integer>();
set.add(3.45); //NOT ok.
Lars Andren
źródło
7

Oto kolejny przypadek, w którym gryzą cię surowe typy:

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();
  }
}

Jak wspomniano w zaakceptowanej odpowiedzi, tracisz wszelką obsługę generyków w kodzie surowego typu. Każdy parametr typu jest konwertowany na jego skasowanie (co w powyższym przykładzie jest po prostu Object).

GuyPaddock
źródło
5

Chodzi o to, że twój listjestList nieokreślonym przedmiotem. Oznacza to, że Java nie wie, jakie obiekty znajdują się na liście. Następnie, gdy chcesz iterować listę, musisz rzucić każdy element, aby mieć dostęp do właściwości tego elementu (w tym przypadku String).

Zasadniczo lepiej jest sparametryzować kolekcje, więc nie masz problemów z konwersją, będziesz mógł dodawać tylko elementy sparametryzowanego typu, a Twój edytor zaoferuje odpowiednie metody wyboru.

private static List<String> list = new ArrayList<String>();
pakore
źródło
4

strona samouczka .

Typ surowy to nazwa ogólnej klasy lub interfejsu bez żadnych argumentów typu. Na przykład biorąc pod uwagę ogólną klasę Box:

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

Aby utworzyć sparametryzowany typ pola, podajesz argument typu rzeczywistego dla formalnego parametru typu T:

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

Jeśli argument typu rzeczywistego zostanie pominięty, tworzony jest surowy typ pola:

Box rawBox = new Box();
Mychajło Adamowicz
źródło
2

Unikaj surowych typów

Typy surowe odnoszą się do używania typu ogólnego bez określania parametru typu.

Na przykład ,

Lista jest typem surowym, a List<String>typem sparametryzowanym.

Kiedy w JDK 1.5 wprowadzono generics, surowe typy zostały zachowane tylko w celu zachowania kompatybilności wstecznej ze starszymi wersjami Javy. Mimo że używanie typów surowych jest nadal możliwe,

Należy ich unikać :

  • Zwykle wymagają rzutów
  • Nie są bezpieczne pod względem typu, a niektóre ważne rodzaje błędów pojawią się tylko w czasie wykonywania
  • Są mniej wyraziste i nie dokumentują się w taki sam sposób jak sparametryzowane typy Przykład

    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));
    
    }
    
    }

W celach informacyjnych : https://docs.oracle.com/javase/tutorial/java/generics/rawTypes.html

Ashish
źródło
1

Znalazłem tę stronę po kilku przykładowych ćwiczeniach i dokładnie takiej samej zagadce.

============== Poszedłem z tego kodu, jak zapewnia przykład ===============

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());
    }

====================== Do tego kodu ========================

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());
    }

}

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

Może być bezpieczniej, ale demontaż filozofii zajął 4 godziny ...

użytkownik2442615
źródło
0

Surowe typy są w porządku, gdy wyrażają to, co chcesz wyrazić.

Na przykład funkcja deserializacji może zwrócić a List, ale nie zna typu elementu listy. Tak Listjest tutaj odpowiedni typ zwrotu.

Stefan Reich
źródło
Możesz użyć ? jako parametr typu
Dániel Kis
Tak, ale to więcej do pisania i jestem przeciwny pisaniu więcej. :)
Stefan Reich,