J'ai besoin d'une carte pour faire un cache en Java pour les mêmes valeurs que j'ai deux clés de chaîne. Ma question Il est préférable de faire des cartes imbriquées (une pour chaque touche) ou de créer un type de clé personnalisé fabriqué avec les deux chaînes? P>
L'accès aux données sur le cache y accédera tous fois avec les deux clés et je n'ai pas besoin de le grouper par aucune de ces deux clés. P>
Ensuite, si c'est mieux combiner la clé de chaîne en un seul de quoi c'est mieux? P>
gethash code>. Mais alors le problème est ce que la fonction de hachage est mise en œuvre? LI>
-
Concaténer simplement deux cordes ensemble. Par exemple: p>
cache.put (clé1 + key2, valeur) p> li>
ul>
6 Réponses :
Utiliser des clés combinées semble plus logique pour moi et plus facile à utiliser (vous n'avez pas à vous soucier de la carte imbriquée d'être instantanée). P>
À propos de la combinaison des touches, utilisez une classe personnalisée. Il a plus de sens sémantiquement et empêche les colis que si vous avez des chaînes similaires. Une telle colision pourrait apparaître si vous avez la clé N'oubliez pas que lorsque vous écrivez votre classe personnalisée, vous devez écrire le ["AB", "C"] code> et la clé
["A", "BC"] P>. P>.
Equals code> et
méthodes code> correctement, ou votre cache pourrait ne pas fonctionner (et pourrait subir des problèmes de performance. ). p>
Il est préférable de créer des cartes imbriquées (une pour chaque touche) ou de faire un type de clé personnalisé fabriqué avec les deux chaînes? P> blockQuote>
Une seule hache avec un type de clé composite peut avoir une meilleure localité de référence. Cela prendra presque moins de mémoire et sera un peu plus rapide, bien que cela dépend de votre application. P>
La conception d'une fonction de hachage personnalisée peut être délicate, mais vous pouvez commencer par une fonction qui prend simplement les hachages déjà définis des membres de la clé composite et les xors les ensemble. Vous pouvez également prendre la route à cordes, mais assurez-vous de concaténer les membres avec un marqueur entre eux (tels que ": em>"), il est peu probable de se produire dans eux. P>
Vous pouvez simplement créer des cartes imbriquées ou utiliser une classe personnalisée définissant Ce n'est généralement pas une bonne idée de concaténer les clés, vous pouvez vous retrouver avec des collisions, comme dans le Cas avec clés Si vous utilisez toujours les deux clés, à l'aide d'une seule carte N'oubliez pas de définir hashcode () code>.
1 code> et
22 code> et des touches
12 code> et
2 code>. Ils mappaient à la même valeur
122 code>. P>
code> sera toujours un peu plus efficace, et vous pouvez toujours définir votre propre adaptateur à la carte qui prendra deux arguments: p>
égale () code> et
et
hashcode () code> dans votre classe de clé personnalisée (ajouter des chèques pour la nullité si nécessaire). P>
public int hashCode() {
int result = 17;
result = 37 * result + keyA.hashCode();
result = 37 * result + keyB.hashCode();
return result;
}
public boolean equals(Object another) {
return another.keyA.equals(keyA) && another.keyB.equals(keyB);
}
Je pense que l'utilisation de cartes imbriquées est moins optimale.
Je suis d'accord avec votre deuxième pensée - implémentez une classe personnalisée avec la nervation n'oublie pas non plus de remplacer les mêmes méthodes de la classe d'objet stockée. p> alors, en cas de ["AB", "C "] Vous aurez le même code de hachage, mais différents sont égaux de résultat p> p> hashcode code>
et est égal à code>
p>
Vous voudrez peut-être envisager de Guava Table cours. Ils implémentent une carte code> avec deux clés par valeur. Cela peut fournir une solution plus lisible qu'une clé composite en fonction de vos besoins.
Table<String, String, MyValue>
Merci beaucoup, c'était exactement ce que je cherchais! Seulement trébuché sur les multimaps de Guava, ce qui n'était pas assez pratique pour moi. ;)
Une note sur HashbasedTable de Guava, il utilise une approche de carte imbriquée.
Peut-il être stocké dans Redis?
J'ai eu un problème similaire avec un système de mise en cache qui devait utiliser des paramattres de méthode pour la génération de clé. J'ai fini par écrire une classe d'enveloppe similaire à la réponse de Xavi.
public final class ArrayWrapper { private final Object[] array; public ArrayWrapper(final Object... array) { this.array = array; } public Object[] getArray() { return this.array; } public boolean equals(Object o) { if (o == null) return false; if (o == this) return true; if (o instanceof ArrayWrapper) { return Arrays.equals(this.array, ((ArrayWrapper)o).array); } return false; } private int hashCode(Object o) { if (o == null) return 0; return o.hashCode(); } public int hashCode() { int sum = 17; if (this.array != null) for(int i = 0;i<this.array.length;i++) { sum = 37 * sum + this.hashCode(this.array[i]); } return sum; } public String toString() { if (this.array != null) { return "Wrapper " + Arrays.toString(array); } else return "Wrapper []"; } }