Une meilleure sécurité de type dans les collections Java
-
22-09-2019 - |
Question
Dans mon codage java, je finis souvent avec plusieurs Map<String,Map<String,foo>>
ou Map<String,List<String>>
, puis-je rappeler la difficulté qui est cordes qui touche. Je commente la déclaration avec //Map<capabiltyId,Map<groupId,foo>>
ou //Map<groupId,List<capabilityId>
, mais ce n'est pas la plus grande solution. Si la chaîne n'était pas définitive, je fais de nouvelles classes CapabilityId extends String
et GroupId extends String
, mais je ne peux pas. Y at-il une meilleure façon de garder une trace des choses est la clé et peut-être le compilateur appliquer?
La solution
Au lieu d'avoir CapabilityId
étendre String
, CapabilityId
pourrait inclure un champ de String
appelé "id"; alors votre Map
pourrait être définie comme Map<CapabilityId, Map<GroupId, Foo>>
, et vous pourriez obtenir les champs d'identification individuels par une getId()
sur vos classes clés.
Je ne suis pas sûr que je ferais moi-même, mais si je l'ai fait, cela est probablement ce que je ferais.
Vous pouvez limiter l'encombrement en ayant une classe abstract GenericId
avec une méthode de champ id et getId()
, et ont CapabilityId
et GroupId
en héritent.
Autres conseils
chaînes Enveloppez dans wrapper classes si vous voulez:
class GroupId implements Comparable {
private String groupId;
public GroupId (String groupId) {
this.groupId = groupId;
}
...
}
Map<GroupId, List<CapabilityId>> m = ...
Créer une classe ID
que vous pouvez sous-classe, et qui se compose d'un champ de String
et mises en œuvre de equals()
et hashCode()
qui utilisent ce domaine.
Je mettrais tout en classe unique et utiliser des champs sensibles / méthode / noms d'argument.
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 cette façon, vous pouvez le voir au nom méthode argument / ce qu'il attend / retours.
Il y a un certain nombre de façons d'aller sur celui-ci (certains déjà mentionné):
- Comme @Roman, envelopper le type d'usage général dans un type plus spécifique, ce qui donne à taper plus fort. bon typage fort, OMI.
- Comme @nanda, utilisez un type de collection plus spécifique. La bibliothèque Java est un peu pauvre dans ce domaine. Cela dépend de la façon dont vous vous sentez sur les dépendances.
- Comme @BalusC, déplacez tous les trucs dégueulasses dans une classe dégueu. Ne retirez pas vraiment le problème, mais il ne contient elle (comme dans Ghostbusters).
-
Map<String,Map<String,foo>>
ressemble beaucoup vous avez une clé composite, à savoir une clé qui comprend deux parties. Donc, introduire une classe clé composite immuable, qui est un objet de valeur représentant les deux objets de valeur des composants.
Au lieu de Map<String,List<String>>
vous devez utiliser Multimap de Google Goyave / Collection Google
Ajout aux autres réponses:
Enveloppez.
Il est non seulement une solution à votre problème, mais une bonne idée en général, à savoir éviter simples paramètres. Votre code gagnera la lisibilité, la santé mentale et la maintenabilité. Vous pouvez ajouter toutes sortes de belles propriétés à elle, par exemple déclarer @Immutable. Comme vous l'avez découvert cette façon est mieux de se rappeler et de contrôler. Vous possédez la classe et peut faire tout ce que vous aimez avec.