Question

(S'il vous plaît pas d'autre conseil que je abstrait X plus et ajouter une autre méthode pour cela.)

En C ++, quand j'ai un x variable de type X* et je veux faire quelque chose de spécifique si elle est de type Y* (Y une sous-classe de étant X), je vous écris ceci:

if(Y* y = dynamic_cast<Y*>(x)) {
    // now do sth with y
}

La même chose ne semble pas possible en Java (ou est-ce?).

J'ai lu ce code Java au lieu:

if(x instanceof Y) {
    Y y = (Y) x;
    // ...
}

Parfois, quand vous ne disposez pas d'un x variable, mais il est une expression plus complexe à la place, juste à cause de ce problème, vous avez besoin d'une variable factice en Java:

X x = something();
if(x instanceof Y) {
    Y y = (Y) x;
    // ...
}
// x not needed here anymore

(chose commune est que something() est iterator.next(). Et vous avez vraiment besoin de la variable factice là, vous voyez que vous aussi ne peut pas vraiment appeler cela seulement deux fois.).

vous avez juste parce que vous ne pouvez pas faire la vérification de x à la fois avec la distribution -

Vous ne du tout ici pas vraiment besoin instanceof. Comparez cela à nouveau le code C ++ assez commun:

if(Y* y = dynamic_cast<Y*>( something() )) {
    // ...
}

En raison de cela, je l'ai introduit une fonction castOrNull qui permet d'éviter la x variable factice. Je peux écrire maintenant:

Y y = castOrNull( something(), Y.class );
if(y != null) {
    // ...
}

Mise en œuvre de castOrNull:

public static <T> T castOrNull(Object obj, Class<T> clazz) {
    try {
        return clazz.cast(obj);
    } catch (ClassCastException exc) {
        return null;
    }
}

Maintenant, on m'a dit que en utilisant cette fonction castOrNull de cette façon est une chose du mal à faire . Pourquoi donc? (Ou pour poser la question plus générale:? Vous êtes d'accord et pense aussi que c'est le mal Si oui, pourquoi Ou pensez-vous que ce soit un cas d'utilisation valide (peut-être rare))


Comme l'a dit, je ne veux pas une discussion si l'utilisation de ces baissés est une bonne idée du tout. Mais permettez-moi de préciser brièvement pourquoi je l'utilise parfois:

  1. Parfois, je reçois dans le cas où je dois choisir entre ajouter une autre nouvelle méthode pour une chose très spécifique (qui ne sera applicable pour une seule sous-classe dans un cas spécifique) ou en utilisant ce contrôle de instanceof. Au fond, j'ai le choix entre l'ajout d'une fonction ou doSomethingVeryVerySpecificIfIAmY() faire la vérification de instanceof. Et dans ce cas, je pense que ce dernier est plus propre.

  2. Parfois, j'ai une collection d'une interface de / classe de base et pour toutes les entrées de type Y, je veux faire quelque chose, puis de les supprimer de la collection. (Par exemple, j'ai eu le cas où j'avais une structure arborescente et je voulais supprimer tous Childs qui sont vides leafs.)

Était-ce utile?

La solution

  

Maintenant, on m'a dit que l'utilisation de cette fonction castOrNull de cette façon est une chose du mal à faire. Pourquoi?

Je peux penser à deux raisons:

  • Il est une manière obscure et difficile de faire quelque chose de très simple. Obscure et le code délicat est difficile à lire, difficile à maintenir, une source potentielle d'erreurs (quand quelqu'un ne comprend pas) et donc mal.

  • La façon obscure et délicate que les travaux de la méthode de castOrNull très probablement ne peuvent pas être optimisés par le compilateur JIT. Vous vous retrouverez avec au moins 3 appels de méthodes supplémentaires, ainsi que beaucoup de code supplémentaire pour faire la vérification de type et jeté pensivement. L'utilisation inutile de la réflexion est le mal.

(En revanche, la manière simple (avec instanceof suivi d'un casting de classe) utilise bytecode spécifiques pour instanceof et la coulée de classe. Les séquences bytecode peuvent presque certainement être optimisés afin qu'il n'y ait pas plus d'un chèque nul et plus qu'un test de type de l'objet dans le code natif. Ceci est un modèle commun qui devrait être facile pour le compilateur JIT pour détecter et optimize.)

Bien sûr, le « mal » est juste une autre façon de dire que

vous ne devriez pas faire vraiment.

Aucune de vos deux exemples supplémentaires, faire usage d'une méthode de castOrNull soit nécessaire ou souhaitable. OMI, la « manière simple » est mieux à la fois des perspectives de lisibilité et de performance.

Autres conseils

Dans la plupart bien écrit / code Java conçu l'utilisation de instanceof et moulages ne se produit jamais. Avec l'ajout de génériques de nombreux cas de moulages (et donc instanceof) ne sont pas nécessaires. Ils le font, à l'occasion se produisent encore.

La méthode castOrNull est mal dans ce que vous faites regard de code Java « contre nature ». Le plus gros problème lors du passage d'une langue à l'autre est l'adoption des conventions de la nouvelle langue. Les variables temporaires sont très bien en Java. En fait toute votre méthode est en train de faire est vraiment cacher la variable temporaire.

Si vous trouvez que vous écrivez beaucoup de moulages vous devez examiner votre code et voir pourquoi et chercher des façons de les supprimer. Par exemple, dans le cas que vous évoquez ajoutez une méthode « getNumberOfChildren » vous permettra de vérifier si un nœud est vide et donc capable de tailler sans coulée (qui est une estimation, il pourrait ne pas fonctionner pour vous dans ce cas).

D'une manière générale sont des moulages « mal » en Java, car ils ne sont généralement pas nécessaires. Votre méthode est plus « mal » parce qu'il est pas écrit de la façon la plupart des gens attendent Java à écrire.

Cela étant dit, si vous voulez le faire, allez-y. Elle ne fait pas « mal » tout simplement pas « bonne » façon de le faire en Java.

IMHO votre castOrNull est pas mal, juste inutile. Vous semblez être obsédé par se débarrasser d'une variable temporaire et une ligne de code, alors que pour moi la plus grande question est pourquoi vous avez besoin tant de downcasts dans votre code ? En OO ce qui est presque toujours un symptôme de la conception suboptimale. Et je préférerais résoudre la cause racine au lieu de traiter le symptôme.

Je ne sais pas exactement pourquoi la personne a dit qu'il était mauvais. Cependant une possibilité pour leur raisonnement était le fait que vous attrapez une exception après plutôt que de vérifier avant de Casted. Ceci est une façon de le faire.

public static <T> T castOrNull(Object obj, Class<T> clazz) {
    if ( clazz.isAssignableFrom(obj.getClass()) ) {
        return clazz.cast(obj);
    } else {
        return null;
    }
}

Java Des exceptions sont lentes. Si vous essayez d'optimiser vos performances en évitant une double distribution, vous vous tirer une balle dans le pied en utilisant des exceptions au lieu de la logique. Ne jamais se fier à attraper une exception pour quelque chose que vous pouvez raisonnablement vérifier et corriger (exactement ce que vous faites).

Comment sont lents exceptions Java?

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