recorrer - map string string java
¿Por qué los valores de HashMap no se incluyen en la lista? (9)
Estoy poniendo valores en el hashmap que es de la forma,
Map<Long, Double> highLowValueMap=new HashMap<Long, Double>();
highLowValueMap.put(1l, 10.0);
highLowValueMap.put(2l, 20.0);
Quiero crear una lista usando el método de mapa values()
.
List<Double> valuesToMatch=new ArrayList<>();
valuesToMatch=(List<Double>) highLowValueMap.values();
o
List<Double> valuesToMatch=(List<Double>) highLowValueMap.values();
Sin embargo, arroja una excepción:
Excepción en el hilo "main" java.lang.ClassCastException:
java.util.HashMap $ Los valores no se pueden convertir en java.util.List
Pero me permite pasarlo a la creación de una lista:
List<Double> valuesToMatch = new ArrayList<Double>( highLowValueMap.values());
TL; DR
List<V> al = new ArrayList<V>(hashMapVar.values());
Explicación
Debido a que HashMap#values()
devuelve java.util.Collection<V>
y no puede convertir una Collection
en ArrayList
, obtiene ClassCastException
.
Sugeriría usar el constructor ArrayList(Collection<? extends V>)
. Este constructor acepta un objeto que implementa Collection<? extends V>
Collection<? extends V>
como argumento. No obtendrá ClassCastException
cuando pase el resultado de HashMap.values()
esta manera:
List<V> al = new ArrayList<V>(hashMapVar.values());
Ir más allá en el código fuente de la API de Java
Valores de HashMap # (): compruebe el tipo de devolución en el origen y pregúntese: ¿puede un java.util.Collection
insertarse en java.util.ArrayList
? No
public Collection<V> values() {
Collection<V> vs = values;
return (vs != null ? vs : (values = new Values()));
}
ArrayList (Colección): verifica el tipo de argumento en la fuente. ¿Puede un método cuyo argumento es un súper tipo aceptar subtipo? Sí
public ArrayList(Collection<? extends E> c) {
elementData = c.toArray();
size = elementData.length;
// c.toArray might (incorrectly) not return Object[] (see 6260652)
if (elementData.getClass() != Object[].class)
elementData = Arrays.copyOf(elementData, size, Object[].class);
}
¿Has comprobado la API, lo que devuelve el método http://docs.oracle.com/javase/6/docs/api/java/util/HashMap.html#values%28%29 ? ¿Y qué constructor ArrayList acepta?
Bueno, es porque tus valores son realmente un HashSet. Podría escribir un código como este para iterar sobre el conjunto:
List<Double> valuesToMatch=new ArrayList<>();
for(Double d : highLowValueMap.values(){
valuesToMatch.put(d);
}
Dudo la mejor respuesta seleccionada, donde dice: "Debido a que HashMap # values () devuelve java.util.Collection y no se puede convertir una Collection en ArrayList, se obtiene ClassCastException".
No se debe a que Colección no se pueda convertir en ArrayList, la verdadera razón es que la Colección devuelta por HashMap.values () está respaldada por la clase interna HashMap.Values. Y HashMap.Values no es una súper clase de ArrayList.
Enfrenté el mismo problema, pero luego me di cuenta de que los valores () devuelven Collection y no List. Pero podemos instanciar una nueva ArrayList como esta:
List valuesToMatch = new ArrayList (highLowValueMap.values ());
Porque ArrayList tiene un constructor que puede tomar Collection como su argumento.
Es porque values()
devuelve Collection
que, de acuerdo con el código fuente de HashMap
es de tipo AbstractCollection
y, por lo tanto, no se puede convertir a List
.
Puede instanciar ArrayList
pasando su resultado values()
porque el constructor ArrayList
puede tomar Collection
como su argumento.
La respuesta se puede encontrar leyendo el JavaDoc
El método values()
devuelve una Collection
Asi que
List<Double> valuesToMatch=(List<Double>) highLowValueMap.values();
Debiera ser
Collection<Double> valuesToMatch= highLowValueMap.values();
Todavía puede iterar sobre esta colección como lo haría con una lista.
http://docs.oracle.com/javase/6/docs/api/java/util/HashMap.html#values%28%29
Esto funciona:
List<Double> valuesToMatch = new ArrayList<Double>( highLowValueMap.values() );
Porque ArrayList
tiene un constructor que acepta una colección.
Si ya ha creado una instancia de su subtipo List (por ejemplo, ArrayList, LinkedList), puede usar el método addAll.
p.ej,
valuesToMatch.addAll(myCollection)
Muchos subtipos de listas también pueden tomar la colección fuente en su constructor.
Values
es una clase interna en la clase HashMap
(ver $ symbol en java.util.HashMap$Values
).
El método HashMap.values () devolverá el objeto de la clase Values
que no está implementando la interfaz de la List
. Lo mismo ClassCastException
.
Aquí está la clase privada interna Values
en HashMap que no está implementando la interfaz de List
. Incluso AbstractCollection tampoco implementa la interfaz de List
.
AbstractCollection
implementa la interfaz de Collection
. Por lo tanto, no se puede convertir a la List
.
private final class Values extends AbstractCollection<V> {
public Iterator<V> iterator() {
return newValueIterator();
}
public int size() {
return size;
}
public boolean contains(Object o) {
return containsValue(o);
}
public void clear() {
HashMap.this.clear();
}
}
Actualizar
Lo siguiente es uno de los constructores en ArrayList.
public ArrayList(Collection<? extends E> c) {
elementData = c.toArray();
size = elementData.length;
// c.toArray might (incorrectly) not return Object[] (see 6260652)
if (elementData.getClass() != Object[].class)
elementData = Arrays.copyOf(elementData, size, Object[].class);
}
El tipo de devolución del método hashmapObj.values()
es Collection
. Ahora, ¿qué clase está implementando esta interfaz de Colección? La respuesta es clase de Values
que está dentro de la clase HashMap (clase interna). El valor devuelto de hashmapObj.values()
se puede pasar al constructor ArrayList anterior, que es válido.
Incluso lo siguiente son declaraciones válidas.
HashMap<String, String> map = new HashMap<String, String>();
Collection c = map.values();
Pero las siguientes declaraciones son incorrectas
HashMap<String, String> map = new HashMap<String, String>();
List c = map.values(); //compilation error.. return type is not List