O que é um tipo bruto e por que não devemos usá-lo?

662

Questões:

  • O que são tipos brutos em Java e por que geralmente ouço que eles não devem ser usados ​​no novo código?
  • Qual é a alternativa se não podemos usar tipos brutos e como é melhor?
poligenelubricants
fonte
os tutoriais java ainda usam o JComboBox que causa esse aviso. Qual versão da caixa de combinação não causará esse aviso? docs.oracle.com/javase/tutorial/uiswing/components/…
SuperStar
1
Observe que a razão pela qual os tipos brutos existem é a compatibilidade com versões anteriores do Java 1.4 e anteriores, que não possuíam genéricos.
Jesper

Respostas:

744

O que é um tipo bruto?

A Java Language Specification define um tipo bruto da seguinte maneira:

Tipos brutos do JLS 4.8

Um tipo bruto é definido como um dos seguintes:

  • O tipo de referência que é formado assumindo o nome de uma declaração de tipo genérica sem uma lista de argumentos de tipo associada.

  • Um tipo de matriz cujo tipo de elemento é um tipo bruto.

  • Um statictipo não membro de um tipo bruto Rque não é herdado de uma superclasse ou superinterface de R.

Aqui está um exemplo para ilustrar:

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

Aqui, MyType<E>é um tipo parametrizado ( JLS 4.5 ). É comum referir-se coloquialmente a esse tipo simplesmente como MyTypeabreviação, mas tecnicamente o nome é MyType<E>.

mttem um tipo bruto (e gera um aviso de compilação) pelo primeiro marcador na definição acima; inntambém tem um tipo bruto pelo terceiro marcador.

MyType.Nestednão é um tipo parametrizado, mesmo que seja um tipo de membro de um tipo parametrizado MyType<E>, porque é static.

mt1e mt2são declarados com parâmetros de tipo reais, portanto, não são tipos brutos.


O que há de tão especial nos tipos brutos?

Essencialmente, os tipos brutos se comportam exatamente como eram antes da introdução dos genéricos. Ou seja, o seguinte é totalmente legal em tempo de compilação.

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

O código acima funciona muito bem, mas suponha que você também tenha o seguinte:

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

Agora, enfrentamos problemas no tempo de execução, porque namescontém algo que não é instanceof String.

Presumivelmente, se você quiser namesconter apenas String, talvez ainda possa usar um tipo bruto e verificar manualmente todos os itens adde depois converter manualmente para Stringtodos os itens de names. Melhor ainda, NÃO é usar um tipo bruto e deixar o compilador fazer todo o trabalho para você , aproveitando o poder dos genéricos Java.

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

Claro, se você NÃO quer namespara permitir que um Boolean, então você pode declará-lo como List<Object> names, e o código acima seria compilar.

Veja também


Como um tipo bruto é diferente de usar <Object>como parâmetros de tipo?

A seguir, uma citação do Effective Java 2nd Edition, Item 23: Não use tipos brutos no novo código :

Qual é a diferença entre o tipo bruto Liste o tipo parametrizado List<Object>? Em termos gerais, o primeiro optou pela verificação de tipo genérico, enquanto o último disse explicitamente ao compilador que é capaz de armazenar objetos de qualquer tipo. Enquanto você pode passar um List<String>a um parâmetro do tipo List, você não pode passá-lo para um parâmetro do tipo List<Object>. Existem regras de subtipagem para genéricos e List<String>é um subtipo do tipo bruto List, mas não do tipo parametrizado List<Object>. Como conseqüência, você perde a segurança de tipo se usar um tipo bruto List, mas não se usar um tipo parametrizadoList<Object> .

Para ilustrar o ponto, considere o método a seguir, que pega a List<Object>e acrescenta a new Object().

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

Os genéricos em Java são invariantes. A List<String>não é a List<Object>, portanto, o seguinte geraria um aviso do compilador:

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

Se você tivesse declarado usar appendNewObjectum tipo bruto Listcomo parâmetro, isso seria compilado e, portanto, você perderia a segurança de tipo obtida dos genéricos.

Veja também


Qual a diferença entre um tipo bruto e o uso <?>como parâmetro de tipo?

List<Object>, List<String>etc são todos List<?>, portanto, pode ser tentador dizer que eles são apenas o Listcontrário. No entanto, há uma grande diferença: como a List<E>define apenas add(E), você não pode adicionar qualquer objeto arbitrário a List<?>. Por outro lado, como o tipo bruto Listnão possui segurança de tipo, você pode addpraticamente qualquer coisa para a List.

Considere a seguinte variação do snippet anterior:

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

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

O compilador fez um trabalho maravilhoso ao proteger você de violar potencialmente a invariância de tipo do List<?>! Se você tivesse declarado o parâmetro como o tipo bruto List list, o código seria compilado e você violaria o tipo invariante List<String> names.


Um tipo bruto é o apagamento desse tipo

Voltar para JLS 4.8:

É possível usar como um tipo o apagamento de um tipo parametrizado ou o apagamento de um tipo de matriz cujo tipo de elemento é um tipo parametrizado. Esse tipo é chamado de tipo bruto .

[...]

As superclasses (respectivamente, superinterfaces) de um tipo bruto são apagamentos das superclasses (superinterfaces) de qualquer uma das parametrizações do tipo genérico.

O tipo de construtor, método de instância ou não staticcampo de um tipo bruto Cque não é herdado de suas superclasses ou superinterfaces é o tipo bruto que corresponde ao apagamento de seu tipo na declaração genérica correspondente a C.

Em termos mais simples, quando um tipo bruto é usado, os construtores, métodos de instância e não staticcampos também são apagados .

Veja o seguinte exemplo:

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

Quando usamos o cru MyType, ele também getNamesé apagado, para que ele retorne um cru List!

O JLS 4.6 continua explicando o seguinte:

O apagamento de tipo também mapeia a assinatura de um construtor ou método para uma assinatura que não possui tipos ou variáveis ​​de tipo parametrizados. O apagamento de uma assinatura de construtor ou método sé uma assinatura que consiste no mesmo nome se no apagamento de todos os tipos de parâmetros formais fornecidos em s.

O tipo de retorno de um método e os parâmetros de tipo de um método ou construtor genérico também sofrem apagamento se a assinatura do método ou construtor for apagada.

O apagamento da assinatura de um método genérico não possui parâmetros de tipo.

O relatório de bug a seguir contém algumas reflexões de Maurizio Cimadamore, um desenvolvedor de compiladores, e Alex Buckley, um dos autores do JLS, sobre por que esse tipo de comportamento deve ocorrer: https://bugs.openjdk.java.net/browse / JDK-6400189 . (Em resumo, isso simplifica a especificação.)


Se não é seguro, por que é permitido usar um tipo bruto?

Aqui está outra citação do JLS 4.8:

O uso de tipos brutos é permitido apenas como uma concessão à compatibilidade do código legado. O uso de tipos brutos no código escrito após a introdução da genéricos na linguagem de programação Java é fortemente desencorajado. É possível que versões futuras da linguagem de programação Java não permitam o uso de tipos brutos.

O Java 2nd Edition eficaz também tem isso a acrescentar:

Como você não deve usar tipos brutos, por que os designers de idiomas os permitiram? Para fornecer compatibilidade.

A plataforma Java estava prestes a entrar em sua segunda década, quando os genéricos foram introduzidos, e havia uma enorme quantidade de código Java existente que não usava genéricos. Foi considerado crítico que todo esse código permaneça legal e interoperável com o novo código que usa genéricos. Tinha que ser legal passar instâncias de tipos parametrizados para métodos projetados para uso com tipos comuns e vice-versa. Esse requisito, conhecido como compatibilidade de migração , levou a decisão de oferecer suporte a tipos brutos.

Em resumo, os tipos brutos NUNCA devem ser usados ​​no novo código. Você sempre deve usar tipos parametrizados .


Não há exceções?

Infelizmente, como os genéricos Java não são reificados, há duas exceções em que os tipos brutos devem ser usados ​​no novo código:

  • Literais de classe, por exemplo List.class, nãoList<String>.class
  • instanceofoperando, por exemplo o instanceof Set, nãoo instanceof Set<String>

Veja também

poligenelubricants
fonte
16
O que você quer dizer com "genéricos Java não são reificados"?
Carl G
7
Para a segunda exceção, a sintaxe o instanceof Set<?>também é permitida para evitar o tipo bruto (embora seja apenas superficial neste caso).
Paul Bellora
1
Os tipos brutos são muito úteis e reduzem o código padrão no caso de pesquisas JNDI para um bean que estende uma interface. Isso resolve a necessidade de gravar nbeans remotos para cada classe de implementação com código idêntico.
djmj
8
"Não reificado" é outra maneira de dizer que eles são apagados. O compilador sabe quais são os parâmetros genéricos, mas essas informações não são passadas para o bytecode gerado. O JLS requer que os literais de classe não tenham parâmetros de tipo.
Erick G. Hagstrom
2
@OldCurmudgeon Isso é interessante. Quero dizer oficialmente que não é nenhum , porque uma classe literal definida como justa TypeName.class, onde TypeNameé um identificador simples ( jls ). Falando hipoteticamente, acho que também poderia ser. Talvez como uma pista, List<String>.classseja a variante que o JLS chama especificamente de erro do compilador; portanto, se algum dia o adicionarem ao idioma, seria de esperar que esse seja o tipo que eles usam.
Radiodef 19/04
62

O que são tipos brutos em Java e por que geralmente ouço que eles não devem ser usados ​​no novo código?

Tipos brutos são história antiga da linguagem Java. No começo, havia Collectionse eles Objectsnão tinham nada mais e nada menos. Todas as operações Collectionsnecessárias são convertidas Objectpara o tipo desejado.

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

Enquanto isso funcionava na maioria das vezes, erros aconteciam

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

As coleções antigas sem tipo não podiam impor a segurança de tipo; portanto, o programador precisava se lembrar do que armazenava em uma coleção.
Onde os genéricos foram inventados para contornar essa limitação, o desenvolvedor declararia o tipo armazenado uma vez e o compilador o faria.

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

Para comparação:

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

Mais complexa a interface Comparável:

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

Observe que é impossível implementar o CompareAble interface com compareTo(MyCompareAble)tipos brutos. Por que você não deve usá-los:

  • Qualquer Object arquivo armazenado em um Collectiondeve ser convertido para poder ser usado
  • O uso de genéricos permite verificações do tempo de compilação
  • Usar tipos brutos é o mesmo que armazenar cada valor como Object

O que o compilador faz: os genéricos são compatíveis com versões anteriores, eles usam as mesmas classes java que os tipos brutos. A mágica acontece principalmente em tempo de compilação.

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

Será compilado como:

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

Este é o mesmo código que você escreveria se usasse os tipos brutos diretamente. Embora não tenha certeza do que acontece com a CompareAbleinterface, acho que ela cria duas compareTofunções, uma tendo umMyCompareAble e outra pegando uma Objecte passando para a primeira após a transmissão.

Quais são as alternativas para os tipos brutos: usar genéricos

josefx
fonte
30

Um tipo bruto é o nome de uma classe ou interface genérica sem nenhum argumento de tipo. Por exemplo, dada a classe Box genérica:

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

Para criar um tipo parametrizado de Box<T>, você fornece um argumento de tipo real para o parâmetro de tipo formal T:

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

Se o argumento de tipo real for omitido, você cria um tipo bruto de Box<T>:

Box rawBox = new Box();

Portanto, Boxé o tipo bruto do tipo genéricoBox<T> . No entanto, uma classe ou tipo de interface não genérico não é um tipo bruto.

Os tipos brutos aparecem no código legado porque muitas classes de API (como as classes Collections) não eram genéricas antes do JDK 5.0. Ao usar tipos brutos, você basicamente obtém um comportamento pré-genérico - a Boxfornece Objects. Para compatibilidade com versões anteriores, é permitido atribuir um tipo parametrizado ao seu tipo bruto.

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

Mas se você atribuir um tipo bruto a um tipo parametrizado, receberá um aviso:

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

Você também receberá um aviso se usar um tipo bruto para chamar métodos genéricos definidos no tipo genérico correspondente:

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

O aviso mostra que os tipos brutos ignoram as verificações de tipo genérico, adiando a captura de código não seguro para o tempo de execução. Portanto, você deve evitar o uso de tipos brutos.

A seção Eliminação de tipo tem mais informações sobre como o compilador Java usa tipos brutos.

Mensagens de erro não verificadas

Como mencionado anteriormente, ao misturar código legado com código genérico, você pode encontrar mensagens de aviso semelhantes à seguinte:

Nota: Example.java usa operações não verificadas ou inseguras.

Nota: Recompile com -Xlint: desmarcado para obter detalhes.

Isso pode acontecer ao usar uma API mais antiga que opera em tipos brutos, conforme mostrado no exemplo a seguir:

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

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

O termo "desmarcado" significa que o compilador não possui informações de tipo suficientes para executar todas as verificações de tipo necessárias para garantir a segurança do tipo. O aviso "desmarcado" está desabilitado, por padrão, embora o compilador dê uma dica. Para ver todos os avisos "desmarcados", recompile com -Xlint: desmarcado.

Recompilar o exemplo anterior com -Xlint: desmarcado revela as seguintes informações adicionais:

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

Para desativar completamente os avisos não verificados, use o sinalizador -Xlint: -unchecked. A @SuppressWarnings("unchecked")anotação suprime avisos não verificados. Se você não estiver familiarizado com o@SuppressWarnings sintaxe, consulte Anotações.

Fonte original: Java Tutorials

Adelin
fonte
21

Um tipo "bruto" em Java é uma classe que não é genérica e lida com objetos "brutos", em vez de parâmetros de tipo genérico com segurança de tipo.

Por exemplo, antes que os genéricos Java estivessem disponíveis, você usaria uma classe de coleção como esta:

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

Quando você adiciona seu objeto à lista, ele não se importa com o tipo de objeto e, quando o obtém da lista, é necessário convertê-lo explicitamente no tipo que você espera.

Usando genéricos, você remove o fator "desconhecido", porque você deve especificar explicitamente quais tipos de objetos podem entrar na lista:

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

Observe que, com os genéricos, você não precisa converter o objeto proveniente da chamada get, a coleção é predefinida para funcionar apenas com MyObject. Esse fato é o principal fator determinante dos genéricos. Ele altera uma fonte de erros de tempo de execução para algo que pode ser verificado em tempo de compilação.

Andy White
fonte
3
Mais especificamente, um tipo bruto é o que você obtém quando simplesmente omite os parâmetros de tipo para um tipo genérico. Os tipos brutos foram realmente apenas um recurso de compatibilidade com versões anteriores e estão potencialmente sujeitos a remoção. Você pode obter um comportamento semelhante usando? parâmetros curinga.
John Flatness
@zerocrates: semelhante, mas diferente! O uso ?ainda oferece segurança de tipo. Eu cobri isso na minha resposta.
polygenelubricants
19
 private static List<String> list = new ArrayList<String>();

Você deve especificar o parâmetro de tipo.

O aviso informa que os tipos definidos para oferecer suporte aos genéricos devem ser parametrizados, em vez de usar sua forma bruta.

Listé definido para genéricos de apoio: public class List<E>. Isso permite muitas operações com segurança de tipo, que são verificadas em tempo de compilação.

Bozho
fonte
3
Agora substituído por inferência de diamante em Java 7 - #private static List<String> list = new ArrayList<>();
Ian Campbell
14

O que é um tipo bruto e por que geralmente ouço que eles não devem ser usados ​​no novo código?

Um "tipo bruto" é o uso de uma classe genérica sem especificar um ou mais argumentos de tipo para seu (s) tipo (s) parametrizado (s), por exemplo, usando em Listvez deList<String> . Quando os genéricos foram introduzidos no Java, várias classes foram atualizadas para usar os genéricos. O uso dessas classes como um "tipo bruto" (sem especificar um argumento de tipo) permitiu que o código legado ainda fosse compilado.

"Tipos brutos" são usados ​​para compatibilidade com versões anteriores. Seu uso no novo código não é recomendado porque o uso da classe genérica com um argumento de tipo permite uma digitação mais forte, o que por sua vez pode melhorar a compreensibilidade do código e levar à detecção de possíveis problemas anteriormente.

Qual é a alternativa se não podemos usar tipos brutos e como é melhor?

A alternativa preferida é usar classes genéricas como pretendido - com um argumento de tipo adequado (por exemplo List<String>). Isso permite que o programador especifique tipos mais especificamente, transmite mais significado aos futuros mantenedores sobre o uso pretendido de uma variável ou estrutura de dados e permite que o compilador imponha melhor segurança de tipo. Essas vantagens juntas podem melhorar a qualidade do código e ajudar a impedir a introdução de alguns erros de codificação.

Por exemplo, para um método em que o programador deseja garantir que uma variável da lista chamada 'names' contenha apenas Strings:

List<String> names = new ArrayList<String>();
names.add("John");          // OK
names.add(new Integer(1));  // compile error
Bert F
fonte
1
Ah, estou tão tentado a copiar polygenelubricantsas referências "tipo bruto" de stackoverflow.com/questions/2770111/… em minha própria resposta, mas suponho que as deixarei para uso em sua própria resposta.
Bert F
1
sim, eu tenho essencialmente copiado e colado esse segmento em todos os lugares em que as pessoas usam tipos brutos no stackoverflow e, finalmente, decidi ter apenas uma pergunta para referir a partir de agora. Espero que seja uma boa contribuição para a comunidade.
polygenelubricants
1
@polygenelubricants notei - nós batemos algumas das mesmas perguntas :-)
Bert F
1
@ ha9u63ar: De fato. Em geral, respostas concisas e simples são pelo menos tão boas quanto as longas e aceitas.
displayName
O que é "syping mais forte"?
precisa saber é o seguinte
12

O compilador deseja que você escreva isso:

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

porque, caso contrário, você pode adicionar qualquer tipo que desejar list, tornando a instanciação new ArrayList<String>()inútil. Os genéricos Java são apenas um recurso em tempo de compilação; portanto, um objeto criado com new ArrayList<String>()prazer aceitará elementos Integerou JFramese for atribuído a uma referência do "tipo bruto" List- o objeto em si não sabe nada sobre os tipos que deve conter, apenas o compilador.

Michael Borgwardt
fonte
12

Aqui estou considerando vários casos através dos quais você pode esclarecer o conceito

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

Caso 1

ArrayList<String> arré uma ArrayListvariável de referência com o tipo Stringque se refere a um ArralyListObjeto do Tipo String. Isso significa que ele pode conter apenas o tipo String.

É estrito, e Stringnão um tipo bruto, portanto, nunca emitirá um aviso.

    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)

Caso 2

Nesse caso, ArrayList<String> arré um tipo estrito, mas seu Objeto new ArrayList();é um tipo bruto.

    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)

aqui arré um tipo estrito. Portanto, isso gerará um erro de tempo de compilação ao adicionar um integer.

Aviso : - Um Rawobjeto de tipo é referenciado a um Stricttipo de variável referenciada ArrayList.

Caso 3

Nesse caso, ArrayList arré um tipo bruto, mas seu Objeto new ArrayList<String>();é um tipo Estrito.

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

Ele adicionará qualquer tipo de objeto a ele, porque arré um tipo bruto.

Aviso : - Um StrictObjeto de Tipo é referenciado a uma rawVariável referenciada por tipo.

Vikrant Kashyap
fonte
8

Um tipo bruto é a falta de um parâmetro de tipo ao usar um tipo genérico.

O tipo bruto não deve ser usado porque pode causar erros de tempo de execução, como inserir um doubleno que deveria ser um Setdos ints.

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

Ao recuperar as coisas do Set, você não sabe o que está saindo. Vamos supor que você espera que seja tudo ints, para o qual está lançando Integer; exceção em tempo de execução quando odouble 3.45 aparecer.

Com um parâmetro de tipo adicionado ao seu Set, você receberá um erro de compilação de uma só vez. Esse erro de preferência permite que você corrija o problema antes que algo exploda durante o tempo de execução (economizando tempo e esforço).

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

Aqui está outro caso em que tipos brutos o morderão:

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

Como foi mencionado na resposta aceita, você perde todo o suporte a genéricos no código do tipo bruto. Todo parâmetro de tipo é convertido em sua eliminação (que no exemplo acima é apenas Object).

GuyPaddock
fonte
5

O que está dizendo é que você listé um Listobjeto não especificado. Ou seja, o Java não sabe que tipo de objetos estão na lista. Então, quando você quiser iterar a lista, precisará converter todos os elementos, para poder acessar as propriedades desse elemento (neste caso, String).

Em geral, é uma idéia melhor parametrizar as coleções, para que você não tenha problemas de conversão, você poderá adicionar apenas elementos do tipo parametrizado e seu editor oferecerá os métodos apropriados a serem selecionados.

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

página do tutorial .

Um tipo bruto é o nome de uma classe ou interface genérica sem nenhum argumento de tipo. Por exemplo, dada a classe Box genérica:

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

Para criar um tipo parametrizado de Box, você fornece um argumento de tipo real para o parâmetro de tipo formal T:

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

Se o argumento de tipo real for omitido, você cria um tipo bruto de Box:

Box rawBox = new Box();
Mykhaylo Adamovych
fonte
2

Evite tipos brutos

Tipos brutos referem-se ao uso de um tipo genérico sem especificar um parâmetro de tipo.

Por exemplo ,

Uma lista é um tipo bruto, enquanto List<String>é um tipo parametrizado.

Quando os genéricos foram introduzidos no JDK 1.5, os tipos brutos foram retidos apenas para manter a compatibilidade com versões anteriores do Java. Embora o uso de tipos brutos ainda seja possível,

Eles devem ser evitados :

  • Eles geralmente exigem elencos
  • Eles não são do tipo seguro e alguns tipos importantes de erros aparecerão apenas em tempo de execução
  • Eles são menos expressiva, e não fazer auto-documento da mesma forma que tipos parametrizados Exemplo

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

Para referência : https://docs.oracle.com/javase/tutorial/java/generics/rawTypes.html

Ashish
fonte
1

Encontrei esta página depois de fazer alguns exemplos de exercícios e ter exatamente a mesma perplexidade.

============== Eu fui deste código conforme fornecido pela amostra ===============

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

====================== Para este código ========================

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

}

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

Pode ser mais seguro, mas levou 4 horas para desmembrar a filosofia ...

user2442615
fonte
0

Os tipos brutos são bons quando expressam o que você deseja expressar.

Por exemplo, uma função de desserialização pode retornar a List, mas não sabe o tipo de elemento da lista. Assim Listé o tipo de retorno apropriado aqui.

Stefan Reich
fonte
Você pode usar ? como parâmetro de tipo
Dániel Kis
Sim, mas é mais para digitar e sou contra digitar mais. :)
Stefan Reich