Java: manière propre à jeter automatiquement UnsupportedOperationException lors de l'appel hashCode () et equals ()?

StackOverflow https://stackoverflow.com/questions/2205565

  •  18-09-2019
  •  | 
  •  

Question

Nous avons un OO où dans codebase beaucoup de cas hashcode() et equals() ne fonctionnent tout simplement pas, la plupart du temps pour la raison suivante:

  

Il n'y a pas moyen d'étendre un   classe instanciable et ajouter une valeur   composante tout en préservant les égaux   contrat, sauf si vous êtes prêt à   renoncer aux avantages de orienté objet   abstraction.

C'est une citation de « Java efficace » par Joshua Bloch et il y a plus à ce sujet dans un article Artima ici:

http://www.artima.com/lejava/articles/equality.html

Et nous sommes parfaitement bien avec ça, ce n'est pas ce que cette question est au sujet.

La question est: vu qu'il est un fait que, dans certains cas, vous ne pouvez pas honorer le contrat de equals(), ce serait une manière propre à faire automatiquement hashcode() et equals() jeter un UnsupportedOperationException

travaillerais une annotation? Je pense à quelque chose comme @NotNull:. Toute violation du contrat @NotNull ne jette une exception automatiquement et vous avez rien d'autre à faire à part annoter vos paramètres / valeur de retour avec @NotNull

Il est pratique, car il est de 8 caractères ( "@NotNull") au lieu de répéter sans cesse le même code d'exception de vérification / throw.

Dans le cas où je suis préoccupé, dans chaque mise en œuvre où hashCode()/equals() n'a pas de sens, nous répéter toujours la même chose:

@Override
public int hashCode() {
    throw new UnsupportedOperationException( "contract violation: calling hashCode() on such an object makes no sense" );
}

@Override
public boolean equals( Object o ) {
    throw new UnsupportedOperationException( "contract violation: calling equals() on such an object makes no sense" );
}

Cependant ceci est sujette aux erreurs. Nous pouvons par mégarde oublier de couper / coller ce et il peut les résultats dans les utilisateurs abusant de ces objets (par exemple en essayant de les mettre dans la valeur par défaut des collections Java)

Ou si l'annotation ne peut être faite pour créer ce comportement, travailleraient AOP?

Il est intéressant de la vraie question, il la présence de hashCode() et equals() au sommet de la hiérarchie Java qui n'a aucun sens dans certains cas, tout à fait. Mais comment pouvons-nous traitons ce problème proprement?

Était-ce utile?

La solution

Pourquoi ne pas vous laissez votre IDE (Eclipse / NetBeans / IntelliJ) génèrent les méthodes de hashCode() et equals() pour vous. Ils font un très bon travail dans ce domaine.

AOP fonctionne, bien sûr, mais il est une complication assez. Et cela signifie que vous ne serez pas en mesure d'utiliser ces objets avec presque pas de collection ou d'utilité.

L'autre solution logique est de supprimer simplement les mises en œuvre de ces méthodes où ils ne travaillent pas, thsus laissant effectivement que les mises en œuvre dans Object.

Autres conseils

Je suis d'accord avec votre évaluation de ce qui est un problème avec hashCode et equals étant définies dans l'objet en premier lieu. J'ai tenu depuis longtemps que l'égalité doit être traitée de la même manière que la commande -. Avec une interface disant: « Je peux comparer avec une instance de X » et une autre disant: « Je peux comparer deux instances de X »

D'autre part, a cette en fait a causé des bugs pour vous? Les gens ont essayé d'utiliser equals et hashCode où ils ne devraient pas? Parce que même si vous pouvez faire chaque classe dans votre codebase lancer une exception lorsque ces méthodes sont appelées de façon inappropriée, qui ne sera pas vrai d'autres classes que vous utilisez, que ce soit du JDK ou un tiers bibliothèques.

Je suis sûr que vous pouvez le faire avec AOP d'une forme ou une autre, que ce soit le traitement d'annotation normale ou autre chose - mais avez-vous des preuves que la récompense serait en vaut la peine

?

Une autre façon de regarder: c'est que dans le cas où vous étendre une autre classe qui remplace déjà hashCode et equals, non? Sinon, vous pouvez utiliser la nature « égalité = identité » de hashCode de l'objet / equals méthodes, qui peuvent encore être utiles. Avez-vous des très nombreuses classes qui entrent dans cette catégorie? Pourriez-vous pas seulement écrire un test unitaire pour trouver tous ces types par réflexion, et vérifier que ces types jettent une exception lorsque vous appelez hashCode / equals? (Cela pourrait être soit automatisé si elles ont un constructeur parameterless, ou une liste manuelle des types qui ont été vérifiés -. Le test unitaire pourrait échouer s'il y a un nouveau type qui ne figure pas sur la liste « bien connue »)

Je ne vois pas pourquoi vous pensez que « dans certains cas, vous ne pouvez pas satisfaire les contrats égaux () »? Le sens de l'égalité est définie par la classe. Ainsi, en utilisant l'égal de l'objet est tout à fait valable. Si vous n'êtes pas égal à égal alors primordial que vous définissez chaque instance comme étant unique.

Il semble y avoir une idée fausse qui équivaut est l'une de ces méthodes qui a toujours besoin primordial, et qu'il doit vérifier tous ses champs. Je dirais le contraire -. Ne pas remplacer égale à moins que votre définition de l'égalité diffère

Je suis également en désaccord avec l'article Artima, en particulier « Pitfall # 3: La définition est égal en termes de champs mutables ». Il est tout à fait valable pour une classe a défini son égalité fondée sur les champs mutables. Il est l'utilisateur d'être au courant de ce lors de son utilisation avec des collections. Si un objet mutable définit son égalité sur son état mutable, alors ne vous attendez pas deux instances soient égaux quand on a changé.

Je pense que jeter UnsupportedOperation viole le sprint d'égal à égal. de equals états:

  

La méthode equals de la classe Object   met en œuvre les plus exigeants   possible relation d'équivalence sur   objets; qui est, pour toute non nulle   les valeurs de référence x et y, ce procédé   renvoie true si et seulement si x et y   se référer à un même objet (x == y a   la valeur vraie).

Alors, je devrais être en mesure d'appeler égaux et obtenir une valeur vraie ou fausse selon soit la définition de l'objet est égale ou surchargée est égal à la définition.

Il y a au moins deux relations d'équivalence qui peuvent être définies entre tous objets Java ou .NET:

  • Deux références d'objets X et Y sont entièrement équivalentes si X avec un remplaçant référence à Y ne modifierait pas le comportement actuel ou futur de tous les membres de X ou Y.

  • Deux références d'objets X et Y ont l'état équivalent si, dans un programme qui n'a pas persisté les valeurs renvoyées de la fonction de hachage lié à l'identité, en échangeant toutes les références à X avec toutes les références à Y laisserait l'état du programme inchangé.

I ai une référence (X) qui pointe vers un FordBlazer. J'ai une autre (Y) qui pointe vers un SiameseCat. Sont-ils équivalents? Non, ils ne sont pas, donc X.equals(Y) devraient être faux. Le fait que les objets de types de relation ont pas entre eux ne sont pas un problème - si quoi que ce soit, cela rend les choses plus facile (si la seule chose qui peut être équivalent à un SiameseCat est un autre SiameseCat, le fait que Y n'est pas un SiameseCat signifie que X.equals() ne pas examiner quoi que ce soit d'autre.

Bien qu'il puisse y avoir un débat pour savoir si un objet particulier devrait mettre en œuvre la première ou la deuxième définition de l'équivalence, il convient de noter que tout objet qui définit equals rapportent des objets distincts comme inégale indépendamment des autres aspects de leur état sera compatible avec lui-même (si x.Equals (X) ne correspond pas à x.Equals (Y), ce qui signifie que Y ne se comporte pas le même que X). Ainsi, si l'on n'a pas rien de mieux à faire avec equals, la définition par défaut héritée de object est un parfaitement bon et significatif.

La seule situation où hashCode pourrait avoir du mal sera si le code peut (malencontreusement) muter un aspect d'un objet alors qu'il est stocké dans une table de hachage. le remède approprié pour ce qui est d'avoir hashCode ne dépendent des aspects mutables de l'état d'un objet. Si un état de l'objet n'a pas immuables aspects significatifs autres que sa classe, faire tout simplement un nombre arbitraire de cette classe et ont hashCode revenir toujours. Les grandes tables de hachage fonctionnent mal ces objets, mais les petits codes de hachage fonctionnera très bien. Le fait que l'on ne peut pas définir un bon code de hachage pour un type ne devrait pas l'empêcher d'être utilisé dans une table de hachage avec une dizaine d'articles en elle.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top