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?
Respostas:
A Java Language Specification define um tipo bruto da seguinte maneira:
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
static
tipo não membro de um tipo brutoR
que não é herdado de uma superclasse ou superinterface deR
.
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 MyType
abreviação, mas tecnicamente o nome é MyType<E>
.
mt
tem um tipo bruto (e gera um aviso de compilação) pelo primeiro marcador na definição acima; inn
também tem um tipo bruto pelo terceiro marcador.
MyType.Nested
não é um tipo parametrizado, mesmo que seja um tipo de membro de um tipo parametrizado MyType<E>
, porque é static
.
mt1
e mt2
são declarados com parâmetros de tipo reais, portanto, não são 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 names
contém algo que não é instanceof String
.
Presumivelmente, se você quiser names
conter apenas String
, talvez ainda possa usar um tipo bruto e verificar manualmente todos os itens add
e depois converter manualmente para String
todos 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 names
para permitir que um Boolean
, então você pode declará-lo como List<Object> names
, e o código acima seria compilar.
<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
List
e o tipo parametrizadoList<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 umList<String>
a um parâmetro do tipoList
, você não pode passá-lo para um parâmetro do tipoList<Object>
. Existem regras de subtipagem para genéricos eList<String>
é um subtipo do tipo brutoList
, mas não do tipo parametrizadoList<Object>
. Como conseqüência, você perde a segurança de tipo se usar um tipo brutoList
, 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 appendNewObject
um tipo bruto List
como parâmetro, isso seria compilado e, portanto, você perderia a segurança de tipo obtida dos genéricos.
<?>
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 List
contrá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 List
não possui segurança de tipo, você pode add
praticamente 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
.
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
static
campo de um tipo brutoC
que não é herdado de suas superclasses ou superinterfaces é o tipo bruto que corresponde ao apagamento de seu tipo na declaração genérica correspondente aC
.
Em termos mais simples, quando um tipo bruto é usado, os construtores, métodos de instância e não static
campos 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 nomes
e no apagamento de todos os tipos de parâmetros formais fornecidos ems
.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.)
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 .
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:
List.class
, nãoList<String>.class
instanceof
operando, por exemplo o instanceof Set
, nãoo instanceof Set<String>
o instanceof Set<?>
também é permitida para evitar o tipo bruto (embora seja apenas superficial neste caso).
n
beans remotos para cada classe de implementação com código idêntico.
TypeName.class
, onde TypeName
é um identificador simples ( jls ). Falando hipoteticamente, acho que também poderia ser. Talvez como uma pista, List<String>.class
seja 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.
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 Collections
e eles Objects
não tinham nada mais e nada menos. Todas as operações Collections
necessárias são convertidas Object
para 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:
Object
arquivo armazenado em um Collection
deve ser convertido para poder ser usadoObject
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 CompareAble
interface, acho que ela cria duas compareTo
funções, uma tendo umMyCompareAble
e outra pegando uma Object
e passando para a primeira após a transmissão.
Quais são as alternativas para os tipos brutos: usar genéricos
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 Box
fornece Object
s. 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.
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
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.
?
ainda oferece segurança de tipo. Eu cobri isso na minha resposta.
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.
private static List<String> list = new ArrayList<>();
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 List
vez 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
polygenelubricants
as 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.
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 Integer
ou JFrame
se 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.
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>();
ArrayList<String> arr
é uma ArrayList
variável de referência com o tipo String
que se refere a um ArralyList
Objeto do Tipo String
. Isso significa que ele pode conter apenas o tipo String.
É estrito, e String
nã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)
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
Raw
objeto de tipo é referenciado a umStrict
tipo de variável referenciadaArrayList
.
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
Strict
Objeto de Tipo é referenciado a umaraw
Variável referenciada por tipo.
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 double
no que deveria ser um Set
dos int
s.
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 int
s, 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.
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
).
O que está dizendo é que você list
é um List
objeto 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>();
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();
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 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
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 ...
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.