Tengo un Map<String, List<String>>
en mi código, donde evitaría posibles punteros nulos si el método #get()
del mapa devolviera una lista vacía en lugar de nulo. ¿Hay algo como esto en la API de Java? ¿Debo simplemente extender HashMap
?Implementación del mapa Java que devuelve un valor predeterminado en lugar de nulo
Respuesta
@ La respuesta de Jon es una buena manera de hacer lo que está preguntando directamente.
Pero me sorprende que lo que intentas implementar es un "multimap"; es decir, un mapeo de una clave a una colección de valores. Si ese es el caso, entonces también debería mirar las clases multimapa en las colecciones de Guava o Apache commons.
Mira:
- la interfaz
com.google.common.collect.Multimap
y sus implementaciones, o - la interfaz
org.apache.commons.collections.MultiMap
y sus implementaciones. - Interfaz y sus implementaciones (una nueva versión del MultiMap anterior;
+1 Y 'get()' en un 'Multimap' que no contiene la clave devuelve una' Colección' vacía por contrato ... exactamente lo que quiere el OP. Lo mismo no sucede con Apache Commons 'MultiMap' que tiene un comportamiento no especificado. – ColinD
@ColinD cierto. Al usar apache commons, podemos usar DefaultedMap, que devuelve un valor predeterminado cuando el mapa no contiene el valor especificado. – simao
Como se señala en los comentarios:
mapa de computación concepto de guayaba fue reemplazado con
LoadingCache
. También se introdujo Java 8 en la interfaz de Map nicecomputeIfAbsent
método predeterminado que no rompe el contrato del mapa y cuenta con evaluación diferida.
Guava tuvieron la idea de una "hoja de cálculo" que ejecutará una función para proporcionar un valor si no está presente. Se implementó en MapMaker.makeComputingMap
; ahora puede usar CacheBuilder
- vea CacheBuilder.build
para más detalles.
Puede ser excesiva para lo que está buscando - que podría ser mejor simplemente escribiendo una aplicación Map
cuales tiene un Map
(usando la composición en lugar de extender cualquier aplicación particular) y luego simplemente devolver el valor predeterminado si no es presente. Cada método distinto get
probablemente podría simplemente delegar en el otro mapa:
public class DefaultingMap<K, V> implements Map<K, V>
{
private final Map<K, V> map;
private final V defaultValue;
public DefaultingMap(Map<K, V> map, V defaultValue)
{
this.map = map;
this.defaultValue = defaultValue;
}
@Override public V get(Object key)
{
V ret = map.get(key);
if (ret == null)
{
ret = defaultValue;
}
return ret;
}
@Override public int size()
{
return map.size();
}
// etc
}
Cuidado: al hacer esto se rompe el contrato de 'get()': si el mapa no contiene la clave, 'null' se devuelve. Para cumplir, debe anular 'containsKey()' a * always * return 'true'. Asumiría que 'makeComputingMap()' también lo haría, pero no lo encontró explícitamente en los documentos. –
@Mark: Posiblemente. Aunque luego te metes en la dificultad de iterar sobre las teclas, también ... básicamente tarde o temprano la abstracción se rompe. * Donde * lo rompa definitivamente sería una cuestión de profunda consideración :) –
El '// etc' no es pequeño, y hace que esta solución impráctica IMO. –
Me parece que simplemente puede escribir una función de contenedor para obtener el valor que desea y si es null
retorno por defecto en su lugar.
Map<String, List<String>> myMap = new Map<String, List<String>>();
public List<String> myGet(String key) {
List<String> ret = myMap.get(key);
if(ret == NULL) {
return defaultList(); // where defaultList is a function that generates your default list.
}
return ret;
}
Esto supone que su myMap
es una variable global (para simplificar), si eso no es lo que quieres, entonces también se puede extender o Map
HashMap
en algo así como MyMap
y basta con incluir esta función adicional. De esta forma, puede usarlo desde cualquier lugar donde se instancia un objeto MyMap
.
Hmm, el patrón de decorador mencionado anteriormente parece una idea aún mejor ... – Argote
Esto no ayuda mucho si necesita pasar el mapa a algo esperando un Mapa. –
Similar a las publicaciones anteriores, excepto que puede anular el método get si desea cambiar su comportamiento.
Map<String, List<String>> map = new LinkedHashMap<String, List<String>>() {
public String get(Object key) {
List<String> list = super.get(key);
if (list == null && key instanceof String)
super.put(key, list = new ArrayList<String>());
return list;
}
};
Guava tiene un método para hacer exactamente lo que usted desea.Es similar al Argote's answer.
Map<String, List<String>> myMap = ...
Functions.forMap(myMap, Arrays.asList("default", "value"));
Gracias a default
métodos, Java 8 ahora tiene esta construido con Map::getOrDefault
:
Map<Integer, String> map = ...
map.put(1, "1");
System.out.println(map.getOrDefault(1, "2")); // "1"
System.out.println(map.getOrDefault(2, "2")); // "2"
Esta es la respuesta más delgada ya que no requiere guayaba. Y, por cierto, era lo que estaba buscando. Voto ascendente. –
Parece que según el momento esta es la mejor solución, pero llegó muy tarde a la fiesta (¡gracias java 8!). Me gusta su simplicidad. +1 –
- 1. JasperReports: valor predeterminado en lugar de 'nulo'
- 2. deserializar un miembro transitoria de un objeto a un valor predeterminado no nulo en Java
- 3. Registry.LocalMachine.OpenSubKey() devuelve un valor nulo
- 4. Scala: sobrescribir un método Java genérico que se devuelve un valor nulo
- 5. Type.GetType (typeName cadena) devuelve un valor nulo
- 6. Consulta Sqlite que devuelve 0 aunque el valor sea nulo
- 7. getPackageManager() (.getInstalledPackages PackageManager.GET_ACTIVITIES) devuelve un valor nulo
- 8. findViewById (android.R.id.progress) devuelve un valor nulo
- 9. SelectSingleNode siempre devuelve un valor nulo?
- 10. Java - class.getResource devuelve nulo
- 11. Clipboard.GetText devuelve un valor nulo (cadena vacía)
- 12. BitmapFactory.decodeResource devuelve el valor nulo
- 13. el método hibernate query.list() devuelve la lista vacía en lugar del valor nulo
- 14. IE9, Win 7 window.open() devuelve un valor nulo en lugar de referencia de la ventana abierta
- 15. document.getElementbyId() que devuelve nulo
- 16. Diferencia entre nulo predeterminado nulo y nulo predeterminado en mysql?
- 17. Clave en TreeMap que devuelve nulo
- 18. Implementación del mapa de listas ordenadas en Java
- 19. System.getProperty devuelve un valor nulo a la propiedad definida
- 20. ¿Cómo cambiar lo que devuelve el valor predeterminado (T) en C#?
- 21. Implementación de un tiempo de espera en una función que devuelve un valor
- 22. Cómo establecer el valor predeterminado de la cadena vacía TextBox en lugar de nulo
- 23. File.list() devuelve un valor nulo para el directorio
- 24. FacesContext.getCurrentInstance() devuelve un valor nulo en la clase Ejecutable
- 25. Gson ignorando las entradas del mapa con valor = nulo
- 26. BroadcastReceiver para CONNECTIVITY_ACTION siempre devuelve un valor nulo en intent.getExtras()
- 27. Insertar valor predeterminado cuando se inserta nulo
- 28. Android: bitmapfactory.decodestream devuelve nulo
- 29. Eclipse getResourceAsStream que devuelve nulo
- 30. Conversión del mapa de Scala que contiene un mapa booleano a Java que contiene java.lang.Boolean
utilizando el patrón decorador, probablemente sería mejor que HashMap se extiende ... – kem
No le cabe duda, pero ¿por qué sería mejor? –
@jk: ¿Por qué querría limitarse a él * siempre * siendo un HashMap? ¿Qué pasa si a veces quieres un LinkedHashMap? ¿O un ConcurrentHashMap? O un TreeMap? Básicamente, favorecer la composición sobre la herencia :) –