Preguntas:
- ¿Qué son los tipos sin formato en Java y por qué a menudo escucho que no deberían usarse en un código nuevo?
- ¿Cuál es la alternativa si no podemos usar tipos sin formato y cómo es mejor?
Respuestas:
La especificación del lenguaje Java define un tipo sin procesar de la siguiente manera:
Un tipo sin formato se define como uno de:
El tipo de referencia que se forma tomando el nombre de una declaración de tipo genérico sin una lista de argumentos de tipo acompañante.
Un tipo de matriz cuyo tipo de elemento es un tipo sin formato.
Un
static
tipo no miembro de un tipo sin formatoR
que no se hereda de una superclase o superinterfaz deR
.
Aquí hay un ejemplo 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!)
}
}
Aquí, MyType<E>
es un tipo parametrizado ( JLS 4.5 ). Es común referirse coloquialmente a este tipo simplemente MyType
para abreviar, pero técnicamente el nombre es MyType<E>
.
mt
tiene un tipo sin formato (y genera una advertencia de compilación) por el primer punto en la definición anterior; inn
también tiene un tipo sin formato en el tercer punto de viñeta
MyType.Nested
no es un tipo parametrizado, aunque es un tipo de miembro de un tipo parametrizado MyType<E>
, porque lo es static
.
mt1
, y mt2
ambos se declaran con parámetros de tipo reales, por lo que no son tipos sin formato.
Esencialmente, los tipos sin procesar se comportan tal como eran antes de que se introdujeran los genéricos. Es decir, lo siguiente es completamente legal en tiempo de compilación.
List names = new ArrayList(); // warning: raw type!
names.add("John");
names.add("Mary");
names.add(Boolean.FALSE); // not a compilation error!
El código anterior funciona bien, pero supongamos que también tiene lo siguiente:
for (Object o : names) {
String name = (String) o;
System.out.println(name);
} // throws ClassCastException!
// java.lang.Boolean cannot be cast to java.lang.String
Ahora nos encontramos con problemas en tiempo de ejecución, porque names
contiene algo que no es un instanceof String
.
Presumiblemente, si solo desea names
contener String
, tal vez aún podría usar un tipo sin formato y verificar manualmente cada add
uno, y luego emitir manualmente a String
cada elemento desde names
. Aún mejor , aunque NO es usar un tipo sin procesar y dejar que el compilador haga todo el trabajo por usted , aprovechando el poder de los genéricos de Java.
List<String> names = new ArrayList<String>();
names.add("John");
names.add("Mary");
names.add(Boolean.FALSE); // compilation error!
Por supuesto, si QUÉ desea names
para permitir una Boolean
, entonces se puede declarar como List<Object> names
, y el código anterior se compilará.
<Object>
como parámetros de tipo?La siguiente es una cita de Effective Java 2nd Edition, Artículo 23: No use tipos sin procesar en el nuevo código :
¿Cuál es la diferencia entre el tipo sin formato
List
y el tipo parametrizadoList<Object>
? Hablando en términos generales, el primero ha optado por la verificación de tipos genéricos, mientras que el segundo le dijo explícitamente al compilador que es capaz de contener objetos de cualquier tipo. Si bien puede pasarList<String>
a un parámetro de tipoList
, no puede pasarlo a un parámetro de tipoList<Object>
. Hay reglas de subtipo para genéricos, yList<String>
es un subtipo del tipo sin formatoList
, pero no del tipo parametrizadoList<Object>
. Como consecuencia, pierde seguridad de tipo si usa un tipo sin formato comoList
, pero no si usa un tipo con parámetros comoList<Object>
.
Para ilustrar el punto, considere el siguiente método que toma List<Object>
ay agrega a new Object()
.
void appendNewObject(List<Object> list) {
list.add(new Object());
}
Los genéricos en Java son invariables. A List<String>
no es a List<Object>
, por lo que lo siguiente generaría una advertencia de compilación:
List<String> names = new ArrayList<String>();
appendNewObject(names); // compilation error!
Si hubiera declarado appendNewObject
tomar un tipo sin formato List
como parámetro, esto se compilaría y, por lo tanto, perdería la seguridad de tipo que obtiene de los genéricos.
<?>
como parámetro de tipo?List<Object>
, List<String>
etc. son todos List<?>
, por lo que puede ser tentador decir que son simplemente en su List
lugar. Sin embargo, hay una gran diferencia: dado que a List<E>
solo define add(E)
, no puede agregar cualquier objeto arbitrario a a List<?>
. Por otro lado, dado que el tipo sin List
formato no tiene seguridad de tipo, puede add
casi cualquier cosa para a List
.
Considere la siguiente variación del fragmento anterior:
static void appendNewObject(List<?> list) {
list.add(new Object()); // compilation error!
}
//...
List<String> names = new ArrayList<String>();
appendNewObject(names); // this part is fine!
¡El compilador hizo un trabajo maravilloso al protegerlo de violar potencialmente la invariancia de tipo del List<?>
! Si hubiera declarado el parámetro como tipo sin formato List list
, el código se compilaría y violaría el tipo invariante de List<String> names
.
Volver a JLS 4.8:
Es posible utilizar como tipo la eliminación de un tipo parametrizado o la eliminación de un tipo de matriz cuyo tipo de elemento es un tipo parametrizado. Tal tipo se llama tipo crudo .
[...]
Las superclases (respectivamente, superinterfaces) de un tipo sin formato son los borrados de las superclases (superinterfaces) de cualquiera de las parametrizaciones del tipo genérico.
El tipo de constructor, método de instancia o no
static
campo de un tipo sin formatoC
que no se hereda de sus superclases o superinterfaces es el tipo sin formato que corresponde a la eliminación de su tipo en la declaración genérica correspondiente aC
.
En términos más simples, cuando se usa un tipo sin formato, los constructores, los métodos de instancia y los no static
campos también se borran .
Tome el siguiente ejemplo:
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);
}
}
Cuando usamos el raw MyType
, también getNames
se borra, ¡para que devuelva un raw List
!
JLS 4.6 continúa explicando lo siguiente:
El borrado de tipos también asigna la firma de un constructor o método a una firma que no tiene tipos parametrizados o variables de tipo. El borrado de una firma de constructor o método
s
es una firma que consta del mismo nombres
y borra todos los tipos de parámetros formales dados ens
.El tipo de retorno de un método y los parámetros de tipo de un método genérico o constructor también se borran si se borra la firma del método o del constructor.
La eliminación de la firma de un método genérico no tiene parámetros de tipo.
El siguiente informe de error contiene algunas reflexiones de Maurizio Cimadamore, un desarrollador del compilador, y Alex Buckley, uno de los autores de JLS, sobre por qué debería ocurrir este tipo de comportamiento: https://bugs.openjdk.java.net/browse / JDK-6400189 . (En resumen, simplifica la especificación).
Aquí hay otra cita de JLS 4.8:
El uso de tipos sin formato solo se permite como una concesión a la compatibilidad del código heredado. Se desaconseja el uso de tipos sin formato en el código escrito después de la introducción de la genérica en el lenguaje de programación Java. Es posible que futuras versiones del lenguaje de programación Java no permitan el uso de tipos sin formato.
Efectivo Java 2nd Edition también tiene esto para agregar:
Dado que no debe usar tipos sin formato, ¿por qué los diseñadores de idiomas lo permitieron? Para proporcionar compatibilidad.
La plataforma Java estaba a punto de entrar en su segunda década cuando se introdujeron los genéricos, y existía una enorme cantidad de código Java que no usaba genéricos. Se consideró crítico que todo este código siga siendo legal e interoperable con el nuevo código que usa genéricos. Tenía que ser legal pasar instancias de tipos parametrizados a métodos diseñados para su uso con tipos normales, y viceversa. Este requisito, conocido como compatibilidad de migración , llevó a la decisión de admitir tipos sin formato.
En resumen, los tipos sin formato NUNCA deben usarse en un código nuevo. Siempre debe usar tipos parametrizados .
Desafortunadamente, debido a que los genéricos de Java no están reificados, hay dos excepciones en las que se deben usar tipos sin formato en el nuevo código:
List.class
, noList<String>.class
instanceof
operando, por ejemplo o instanceof Set
, noo instanceof Set<String>
o instanceof Set<?>
también permite evitar el tipo sin formato (aunque en este caso solo es superficial).
n
beans remotos para cada clase de implementación con código idéntico.
TypeName.class
, donde TypeName
es un identificador simple ( jls ). Hablando hipotéticamente, supongo que realmente podría ser cualquiera. Tal vez como una pista, List<String>.class
es la variante que JLS llama específicamente un error del compilador, por lo que si alguna vez lo agregan al lenguaje, esperaría que ese sea el que usan.
¿Qué son los tipos sin formato en Java y por qué a menudo escucho que no deberían usarse en un código nuevo?
Los tipos sin procesar son historia antigua del lenguaje Java. Al principio hubo Collections
y no tenían Objects
nada más y nada menos. Cada operación en Collections
los moldes requeridos del Object
tipo deseado.
List aList = new ArrayList();
String s = "Hello World!";
aList.add(s);
String c = (String)aList.get(0);
Si bien esto funcionó la mayor parte del tiempo, ocurrieron errores
List aNumberList = new ArrayList();
String one = "1";//Number one
aNumberList.add(one);
Integer iOne = (Integer)aNumberList.get(0);//Insert ClassCastException here
Las antiguas colecciones sin tipo no podían hacer cumplir la seguridad de tipo, por lo que el programador tuvo que recordar lo que almacenaba dentro de una colección.
Los genéricos se inventaron para evitar esta limitación, el desarrollador declararía el tipo almacenado una vez y el compilador lo haría en su lugar.
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 comparacion:
// 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
Más compleja es la interfaz Comparable:
//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;}
}
Tenga en cuenta que es imposible implementar la CompareAble
interfaz con compareTo(MyCompareAble)
tipos sin formato. Por qué no deberías usarlos:
Object
almacenado en un Collection
debe ser lanzado antes de poder ser utilizado.Object
Lo que hace el compilador: los genéricos son compatibles con versiones anteriores, usan las mismas clases de Java que los tipos sin formato. La magia ocurre principalmente en tiempo de compilación.
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 es el mismo código que escribiría si utilizara los tipos sin formato directamente. Aunque no estoy seguro de lo que sucede con la CompareAble
interfaz, creo que crea dos compareTo
funciones, una toma una MyCompareAble
y la otra toma una Object
y se la pasa a la primera después de lanzarla.
¿Cuáles son las alternativas a los tipos sin procesar: usar genéricos
Un tipo sin formato es el nombre de una clase o interfaz genérica sin ningún tipo de argumento. Por ejemplo, dada la clase genérica Box:
public class Box<T> {
public void set(T t) { /* ... */ }
// ...
}
Para crear un tipo parametrizado de Box<T>
, debe proporcionar un argumento de tipo real para el parámetro de tipo formal T
:
Box<Integer> intBox = new Box<>();
Si se omite el argumento de tipo real, crea un tipo sin formato de Box<T>
:
Box rawBox = new Box();
Por lo tanto, Box
es el tipo sin formato del tipo genérico Box<T>
. Sin embargo, una clase no genérica o tipo de interfaz no es un tipo sin formato.
Los tipos sin formato aparecen en el código heredado porque muchas clases de API (como las clases de Colecciones) no eran genéricas antes de JDK 5.0. Cuando se usan tipos sin procesar, esencialmente se obtiene un comportamiento pre-genérico: a Box
da Object
s. Por compatibilidad con versiones anteriores, se permite asignar un tipo parametrizado a su tipo sin formato:
Box<String> stringBox = new Box<>();
Box rawBox = stringBox; // OK
Pero si asigna un tipo sin formato a un tipo parametrizado, recibirá una advertencia:
Box rawBox = new Box(); // rawBox is a raw type of Box<T>
Box<Integer> intBox = rawBox; // warning: unchecked conversion
También recibe una advertencia si usa un tipo sin procesar para invocar métodos genéricos definidos en el tipo genérico correspondiente:
Box<String> stringBox = new Box<>();
Box rawBox = stringBox;
rawBox.set(8); // warning: unchecked invocation to set(T)
La advertencia muestra que los tipos sin procesar omiten las comprobaciones de tipos genéricos, aplazando la captura de código inseguro en tiempo de ejecución. Por lo tanto, debe evitar el uso de tipos sin formato.
La sección de borrado de tipo tiene más información sobre cómo el compilador de Java usa tipos sin formato.
Como se mencionó anteriormente, al mezclar código heredado con código genérico, puede encontrar mensajes de advertencia similares a los siguientes:
Nota: Example.java utiliza operaciones no verificadas o inseguras.
Nota: Recompile con -Xlint: sin marcar para más detalles.
Esto puede suceder cuando se usa una API anterior que funciona con tipos sin formato, como se muestra en el siguiente ejemplo:
public class WarningDemo {
public static void main(String[] args){
Box<Integer> bi;
bi = createBox();
}
static Box createBox(){
return new Box();
}
}
El término "desmarcado" significa que el compilador no tiene suficiente información de tipo para realizar todas las verificaciones de tipo necesarias para garantizar la seguridad de tipo. La advertencia "sin marcar" está deshabilitada, de forma predeterminada, aunque el compilador da una pista. Para ver todas las advertencias "sin marcar", vuelva a compilar con -Xlint: sin marcar.
Volver a compilar el ejemplo anterior con -Xlint: sin marcar revela la siguiente información adicional:
WarningDemo.java:4: warning: [unchecked] unchecked conversion
found : Box
required: Box<java.lang.Integer>
bi = createBox();
^
1 warning
Para deshabilitar completamente las advertencias no verificadas, use el indicador -Xlint: -unchecked. La @SuppressWarnings("unchecked")
anotación suprime las advertencias no verificadas. Si no está familiarizado con la @SuppressWarnings
sintaxis, vea Anotaciones.
Fuente original: Tutoriales de Java
Un tipo "en bruto" en Java es una clase que no es genérica y trata con objetos "en bruto", en lugar de parámetros de tipo genérico con seguridad de tipo.
Por ejemplo, antes de que los genéricos de Java estuvieran disponibles, usaría una clase de colección como esta:
LinkedList list = new LinkedList();
list.add(new MyObject());
MyObject myObject = (MyObject)list.get(0);
Cuando agrega su objeto a la lista, no le importa qué tipo de objeto es, y cuando lo obtiene de la lista, debe convertirlo explícitamente al tipo que espera.
Usando genéricos, elimina el factor "desconocido", porque debe especificar explícitamente qué tipo de objetos pueden ir en la lista:
LinkedList<MyObject> list = new LinkedList<MyObject>();
list.add(new MyObject());
MyObject myObject = list.get(0);
Tenga en cuenta que con los genéricos no tiene que emitir el objeto proveniente de la llamada get, la colección está predefinida para funcionar solo con MyObject. Este mismo hecho es el principal factor impulsor de los genéricos. Cambia una fuente de errores de tiempo de ejecución en algo que se puede verificar en tiempo de compilación.
?
todavía ofrece seguridad de tipo. Lo cubrí en mi respuesta.
private static List<String> list = new ArrayList<String>();
Debe especificar el tipo-parámetro.
La advertencia informa que los tipos definidos para admitir genéricos deben ser parametrizados, en lugar de usar su forma sin formato.
List
se define a los genéricos de apoyo: public class List<E>
. Esto permite muchas operaciones de tipo seguro, que se verifican en tiempo de compilación.
private static List<String> list = new ArrayList<>();
¿Qué es un tipo sin formato y por qué a menudo escucho que no deberían usarse en un código nuevo?
Un "tipo sin formato" es el uso de una clase genérica sin especificar un argumento de tipo (s) para su tipo (s) parametrizado, por ejemplo, usando en List
lugar de List<String>
. Cuando se introdujeron los genéricos en Java, se actualizaron varias clases para usar los genéricos. El uso de estas clases como un "tipo sin formato" (sin especificar un argumento de tipo) permitió que el código heredado aún se compilara.
Los "tipos sin formato" se utilizan para la compatibilidad con versiones anteriores. No se recomienda su uso en código nuevo porque el uso de la clase genérica con un argumento de tipo permite una escritura más fuerte, lo que a su vez puede mejorar la comprensión del código y conducir a detectar problemas potenciales antes.
¿Cuál es la alternativa si no podemos usar tipos sin formato y cómo es mejor?
La alternativa preferida es utilizar clases genéricas según lo previsto, con un argumento de tipo adecuado (por ejemplo List<String>
). Esto permite que el programador especifique tipos más específicamente, transmite más significado a los futuros mantenedores sobre el uso previsto de una estructura de datos o variable, y permite al compilador hacer cumplir una mejor seguridad de tipos. Estas ventajas juntas pueden mejorar la calidad del código y ayudar a prevenir la introducción de algunos errores de codificación.
Por ejemplo, para un método donde el programador quiere asegurarse de que una variable de Lista llamada 'nombres' contenga solo Cadenas:
List<String> names = new ArrayList<String>();
names.add("John"); // OK
names.add(new Integer(1)); // compile error
polygenelubricants
las referencias de "tipo sin formato " de stackoverflow.com/questions/2770111/… en mi propia respuesta, pero supongo que las dejaré para usar en su propia respuesta.
El compilador quiere que escribas esto:
private static List<String> list = new ArrayList<String>();
porque de lo contrario, podría agregar cualquier tipo que desee list
, haciendo que la instanciación no tenga new ArrayList<String>()
sentido. Los genéricos de Java son solo una característica de tiempo de compilación, por lo que un objeto creado con new ArrayList<String>()
felicidad aceptará elementos Integer
o JFrame
elementos si se les asigna una referencia del "tipo sin formato" List
: el objeto en sí mismo no sabe nada sobre los tipos que se supone que debe contener, solo el compilador lo sabe.
Aquí estoy considerando múltiples casos a través de los cuales puedes aclarar el concepto
1. ArrayList<String> arr = new ArrayList<String>();
2. ArrayList<String> arr = new ArrayList();
3. ArrayList arr = new ArrayList<String>();
ArrayList<String> arr
es una ArrayList
variable de referencia con tipo String
que hace referencia a un ArralyList
Objeto de tipo String
. Significa que solo puede contener objetos de tipo cadena.
Es estricto String
no un tipo sin procesar, por lo que nunca generará una advertencia.
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)
En este caso ArrayList<String> arr
es un tipo estricto pero su objeto new ArrayList();
es un tipo sin formato.
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)
Aquí arr
hay un tipo estricto. Por lo tanto, generará un error de tiempo de compilación al agregar a integer
.
Advertencia : - Un
Raw
objeto de tipo está referenciado a unaStrict
variable de tipo referenciada deArrayList
.
En este caso ArrayList arr
es un tipo sin formato, pero su objeto new ArrayList<String>();
es un tipo estricto.
arr.add("hello");
arr.add(23); //compiles fine but raise the warning.
Agregará cualquier tipo de objeto porque arr
es un tipo sin formato.
Advertencia : - Un
Strict
objeto de tipo está referenciado a unaraw
variable de tipo referenciado.
Un tipo sin formato es la falta de un parámetro de tipo cuando se usa un tipo genérico.
El tipo sin formato no se debe usar porque podría causar errores de tiempo de ejecución, como insertar una double
en lo que se suponía que era una Set
de int
s.
Set set = new HashSet();
set.add(3.45); //ok
Al recuperar las cosas del Set
, no sabes lo que está saliendo. Supongamos que espera que sea todo int
s, lo está emitiendo Integer
; excepción en tiempo de ejecución cuando double
llega el 3.45.
Con un parámetro de tipo agregado a su Set
, obtendrá un error de compilación de inmediato. Este error preventivo le permite solucionar el problema antes de que algo explote durante el tiempo de ejecución (ahorrando así tiempo y esfuerzo).
Set<Integer> set = new HashSet<Integer>();
set.add(3.45); //NOT ok.
Aquí hay otro caso donde los tipos crudos te morderán:
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 se mencionó en la respuesta aceptada, pierde todo el soporte para genéricos dentro del código de tipo sin formato. Cada parámetro de tipo se convierte en su borrado (que en el ejemplo anterior es justo Object
).
Lo que está diciendo es que tu list
es un List
objeto no especificado. Es decir, Java no sabe qué tipo de objetos están dentro de la lista. Luego, cuando desee iterar la lista, debe convertir cada elemento para poder acceder a las propiedades de ese elemento (en este caso, Cadena).
En general, es una mejor idea parametrizar las colecciones, para que no tenga problemas de conversión, solo podrá agregar elementos del tipo parametrizado y su editor le ofrecerá los métodos adecuados para seleccionar.
private static List<String> list = new ArrayList<String>();
Un tipo sin formato es el nombre de una clase o interfaz genérica sin ningún tipo de argumento. Por ejemplo, dada la clase genérica Box:
public class Box<T> {
public void set(T t) { /* ... */ }
// ...
}
Para crear un tipo parametrizado de Box, debe proporcionar un argumento de tipo real para el parámetro de tipo formal T:
Box<Integer> intBox = new Box<>();
Si se omite el argumento de tipo real, crea un tipo sin formato de Box:
Box rawBox = new Box();
Evitar tipos crudos
Los tipos sin formato se refieren al uso de un tipo genérico sin especificar un parámetro de tipo.
Por ejemplo ,
Una lista es un tipo sin formato, mientras que List<String>
es un tipo parametrizado.
Cuando se introdujeron los genéricos en JDK 1.5, los tipos sin formato se conservaron solo para mantener la compatibilidad con versiones anteriores de Java. Aunque todavía es posible usar tipos sin formato,
Deben evitarse :
Son menos expresivos y no se documentan de la misma manera que los tipos parametrizados Ejemplo
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 referencia : https://docs.oracle.com/javase/tutorial/java/generics/rawTypes.html
Encontré esta página después de hacer algunos ejercicios de muestra y tener exactamente el mismo desconcierto.
============== Pasé de este código como lo proporciona la muestra ===============
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());
}
====================== A 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());
}
}
================================================== =============================
Puede ser más seguro, pero tardó 4 horas en desmantelar la filosofía ...
Los tipos sin procesar están bien cuando expresan lo que quieres expresar.
Por ejemplo, una función de deserialización puede devolver a List
, pero no conoce el tipo de elemento de la lista. Entonces, List
es el tipo de retorno apropiado aquí.