Mejor seguridad de tipos de colecciones de Java
-
22-09-2019 - |
Pregunta
En la codificación de mi java, que a menudo terminan con varios Map<String,Map<String,foo>>
o Map<String,List<String>>
y luego tengo problemas para recordar qué cadena es qué tecla. Comento la declaración con //Map<capabiltyId,Map<groupId,foo>>
o //Map<groupId,List<capabilityId>
, pero no es la solución más grande. Si cadena no era definitiva, haría nuevas clases CapabilityId extends String
y GroupId extends String
, pero no puedo. ¿Hay una mejor manera de mantener un registro de qué cosa es la clave y tal vez tiene el compilador hacerla cumplir?
Solución
En lugar de tener CapabilityId
extienden String
, CapabilityId
podría incluir un campo String
llamado "id"; entonces su Map
se podría definir como Map<CapabilityId, Map<GroupId, Foo>>
, y que podría llegar a los campos de ID individuales a través de un getId()
en sus clases principales.
No estoy seguro de que haría esto por mí mismo, pero si lo hiciera, esto es probablemente lo que haría.
Se podría limitar el desorden por tener una clase con un método de abstract GenericId
campo id y getId()
, y tienen CapabilityId
y hereda GroupId
de ella.
Otros consejos
cadenas Envuelva envoltura clases si quieren:
class GroupId implements Comparable {
private String groupId;
public GroupId (String groupId) {
this.groupId = groupId;
}
...
}
Map<GroupId, List<CapabilityId>> m = ...
Crea una clase ID
que puede subclase, y que consiste en un campo String
y las implementaciones de equals()
y hashCode()
que utilizan ese campo.
Me lo pondría todo en una sola clase y hacer uso de los nombres de campo / método / argumentos razonables.
public class GroupCapabilities {
private Map<String, Map<String, Group>> groupCapabilities;
public void addGroup(String capabilityId, Group group) {
Map<String, Group> groups = groupCapabilities.get(capabilityId);
if (groups = null) {
groups = new HashMap<String, Group>();
groupCapabilities.put(capabilityId, group);
}
groups.put(group.getId(), group);
}
public Map<String, Group> getGroups(String capabilityId) {
return groupCapabilities.get(capabilityId);
}
public Group getGroup(String capabilityId, String groupId) {
Map<String, Group> groups = groupCapabilities.get(capabilityId);
return (groups != null) ? groups.get(groupId) : null;
}
// Etc..
}
De esta manera el se puede ver en el método de nombres / argumento lo que espera / devoluciones.
Hay un número de maneras de ir sobre este (algunos ya mencionado):
- Como @Roman, envuelva el tipo de propósito general en un tipo más específico, lo que da a escribir más fuerte. La tipificación estricta buena, la OMI.
- Como @nanda, utilice un tipo de colección más específico. La biblioteca de Java es un poco pobre en esta área. Depende de cómo se siente acerca de las dependencias.
- Como @BalusC, se mueven todas las cosas repulsivo en una clase desordenada. En realidad no eliminar el problema, pero sí lo contienen (como en Ghostbusters).
- miradas
Map<String,Map<String,foo>>
muy parecido que tiene una clave compuesta, es decir, una clave que se compone de dos partes. Por lo tanto, introducir una clase de clave compuesta inmutable, que es un objeto de valor que representa los dos objetos de valor de los componentes.
En lugar de Map<String,List<String>>
se debe utilizar Multimapa de Google Google Colección / guayaba
Adición a las otras respuestas:
Wrap ella.
No es sólo una solución a su problema, sino una idea buena en general, es decir, evitar sencilla parámetros. Su código ganará la legibilidad, la cordura y la facilidad de mantenimiento. Se puede añadir todo tipo de propiedades agradables a la misma, por ejemplo, declarar que @Immutable. Como te enteraste de esta manera es mejor para recordar y control. Es el propietario de la clase y puede hacer lo que quiera con él.