Java Itérateur de mise en œuvre - next() et hasNext() l'exécution de l'ordre
J'ai une mise en œuvre de java.util.Iterator
qui nécessite que l'appel à next()
doit toujours être précédé par un appel à hasNext()
. (C'est parce que les résultats sont renvoyés asynchronosly dans un environnement multithread et il n'est jamais évident de savoir comment beaucoup plus de résultats, il pourrait être).
Serait-il être "correct" pour bien documenter ce dans la JavaDoc et puis jetez un RuntimeException
si cela a été violé. Ou est-ce l'étirement de l'interface Iterator un peu trop loin?
Toutes les pensées apprécié?
Après réflexion, et toutes les réponses que je suis venu à la conclusion que le problème est l'interface Iterator. Il devrait y avoir qu'une méthode next() qui renvoie la valeur null (ou une pilule empoisonnée) lorsqu'il a atteint la fin. Êtes-vous d'accord?
Je suis en désaccord. Tout d'abord, null pourrait être un élément d'un objet iterable. Deuxièmement, compte tenu de type générique d'effacement, comment vous assurez-vous que votre pilule empoisonnée était de type T, mais de toute façon pas un valide valeur de retour? (Je rejette d'emblée toute argumentation où next() ne retourne pas une instance de type T).
Je prends vos points, mais ne pense pas qu'un objet de type Poison ferait aucun mal, même si elle n'est pas de type T. L'alternative (le fait d'avoir deux méthodes) est de loin le pire.
L'nuire à l'objet spécial de type Poison serait la cause de forcer le type de retour de la next() pour changer de T à l'Objet. Qui à son tour serait la cause de tous les appels à côté de faire appel à un instanceOf suivie par un casting. De plus modérément de la taille du projet, c'est une énorme quantité de code réutilisable (exactement le même standard que les génériques étaient censés se débarrasser de dans le la première place. Je ne comprends pas votre problème avec les deux méthodes à la solution, ce qui a un facile de comprendre la méthode pour la vérification des limites, et déclenche une exception lorsque vous faites quelque chose de stupide.
Par la Pilule empoisonnée type, parlez-vous de l'Objet Nul Motif?
Je suis en désaccord. Tout d'abord, null pourrait être un élément d'un objet iterable. Deuxièmement, compte tenu de type générique d'effacement, comment vous assurez-vous que votre pilule empoisonnée était de type T, mais de toute façon pas un valide valeur de retour? (Je rejette d'emblée toute argumentation où next() ne retourne pas une instance de type T).
Je prends vos points, mais ne pense pas qu'un objet de type Poison ferait aucun mal, même si elle n'est pas de type T. L'alternative (le fait d'avoir deux méthodes) est de loin le pire.
L'nuire à l'objet spécial de type Poison serait la cause de forcer le type de retour de la next() pour changer de T à l'Objet. Qui à son tour serait la cause de tous les appels à côté de faire appel à un instanceOf suivie par un casting. De plus modérément de la taille du projet, c'est une énorme quantité de code réutilisable (exactement le même standard que les génériques étaient censés se débarrasser de dans le la première place. Je ne comprends pas votre problème avec les deux méthodes à la solution, ce qui a un facile de comprendre la méthode pour la vérification des limites, et déclenche une exception lorsque vous faites quelque chose de stupide.
Par la Pilule empoisonnée type, parlez-vous de l'Objet Nul Motif?
OriginalL'auteur Dan | 2010-02-01
Vous devez vous connecter pour publier un commentaire.
J'ai peut-être raté quelque chose ici, mais pourquoi ne pas l'appeler
hasNext()
en interne dans votre œuvre?En désaccord: je pense que cet appel à next() sans appeler hasNext() est faux. Je serais de l'application de la généralement reconnus du bon usage.
Je pense que vous n'êtes pas ici. Il est généralement accepté que, dans la plupart des cas, les routines doivent faire le travail leur sont assignées sans dépendre d'un appel à l'ordre. Par exemple, si vous avez un objet de plus de données et que vous voulez calculer un rapport, ne le dis pas l'utilisateur de l'API doit appeler d'abord calculateReport() et ensuite plusieurs fois getReportColumn(). Au lieu de cela calculateReport doit retourner un Rapport-objet, qui permet de accces le rapport-colonnes. Même ici: next() devrait fonctionner sans dépendre d'un appel spécial-commande, en particulier depuis qu'il est spécifié que vous pouvez faire appel à next() seul.
Les itérateurs sont définies dans la bibliothèque avec un ensemble particulier de la sémantique. Toute utilisation conforme à ceux de la sémantique est correct. Lors de la définition de votre propre itérateur si votre sémantiques diffèrent de la norme itérateurs vous êtes probablement à la confusion des utilisateurs et de rendre votre code
harder
. Bien que je ne peux qu'être d'accord que l'utilisation correcte de la vérificationhasNext()
avantnext()
, la bonne réponse à partir de l'itérateur est en train de jeterNoSuchElementException
seulement si il n'y a pas plus d'éléments. Lors de forcer l'exactitude vous devez non seulement besoin de vos utilisateurs, mais aussi à partir de votre propre mise en œuvre.L'interface Iterator n'a pas de mandat d'un appel particulier l'ordre, donc si votre application nécessite que vous violer le contrat de l'interface. Documenter la mise en œuvre n'est pas utile lorsque des instances peuvent être transmises à quelque chose qui n'a pas connaissance de votre application (et peut même précéder).
OriginalL'auteur Fabian Steeg
Exigeant que
hasNext()
être appelée avantnext()
viole lesiterator
contrat. Vous devriez vraiment le réécrire afin quenext()
simplement jette unNoSuchElementException
si il n'y a aucun élément à retour.Parce que
next()
n'a que deux résultats: le retour de la prochaine valeur ou de jeter unNoSuchElementException
quand il n'y a aucun élément suivant. Depuis que vous aviez lancer une exception, même si il y avait un élément suivant, vous êtes violation du contrat.D'accord, jetant le NoSuchElementException est le comportement correct ici. Le hasNext() est une méthode de la garde méthode pour éviter d'avoir à traiter avec l'exception (comme si hasNext() renvoie la valeur true, la prochaine (il ne faut jamais jeter l'exception).
Pour répondre à cette question, pour être complet, je pense qu'il faut vraiment préciser exactement quelle partie de la spécification que vous pensez est violé.
Je pense que vous avez mal compris la question à propos de
RuntimeException
contreNoSuchElementException
, quand il semble vraiment être sur de le jeter ou pas-à-jeter.OriginalL'auteur uckelman
J'imagine que vous êtes en train de faire quelque chose comme ceci:
Que les sons OK pour moi. Je ne peux pas imaginer une situation où vous voulez les utiliser
next
sanshasNext
- ce serait une recette pour les exceptions.EDIT:
La doc pour
hasNext()
dit:Pour moi, la mise en œuvre n'est pas une violation du contrat. Cependant, je voudrais (comme Fabian Steeg implique) continuent de mettre en œuvre
next()
:Je veux dire, ce qui ne fait que vérifier réellement vous coûter?
Vous devez vérifier et de jeter un
NoSuchElementException
que par la API contrat. Analyse sur!hasNext()
ounext == null
permettra de répondre à ce critère, je crois, mais je voudrais faveur de l'ancien.Si quelqu'un est d'attraper
NoSuchElementException
au lieu de l'appelerhasNext()
, vous avez probablement plus de problèmes.par mon interprétation de la documentation, je ne crois pas que cela constitue une violation du contrat.
Joli beaucoup chaque itérateur que j'ai jamais écrit (ce qui est beaucoup) a commencé sa prochaine() mise en œuvre avec les trois lignes de vous illustrer ici.
C'est la bonne réponse, next() doit toujours faire appel à hasNext() tout d'abord, dans l'ensemble, mais la plupart des cas rares. Sinon, il est soit a) la duplication de code, ou b) fait un autre 'hasNext' vérifier en interne que ce que vous fournissez à l'appelant... ce qui est dangereux à partir d'un point de vue de la cohérence.
OriginalL'auteur McDowell
Si votre
hasNext()
etnext()
appels ne sont pas synchronisés bloc/méthode, il n'est pas garanti que vous avez des éléments, même si vous appelezhasNext()
avantnext()
.Le contrat de la
Iterator
interface est queNoSuchElementException
devrait être levée si il n'y a pas plus d'éléments. Afin de procéder avec lanext()
méthode jusqu'à une exception survient.Cela dit, jetez un oeil à la
java.util.simultanées
package - il a les collections simultanées dont les itérateurs peuvent vous aider à - dire que vous pouvez utiliser ces collections et des itérateurs au lieu de la mise en œuvre de votre propre.la même itérateur ne peut pas être utilisé dans deux environnements différents. Si il est accessible par tout moyen à partir de plusieurs threads, alors c'est qu'il einvoronment est multi-thread
OriginalL'auteur Bozho
Je préfère lancer une exception de
next()
, quand il n'y a pas plus d'éléments. Dans un environnement multi-threadhasNext()
est assez inutile de toute façon.Vous n'avez pas besoin de partager le iterator. Le partage de la sous-jacentes collection est assez pour faire de l'itérateur "essentiellement partagée".
Mais oui, en prenant en compte est rare, comme vous l'avez écrit. Mais il y a certainement des exemples concrets d'utilisation d'un thread-safe iterator; par exemple, la vidange d'une file d'attente en utilisant en parallèle des consommateurs. Il est très utile lorsqu'il y a plusieurs processeurs/cœurs en cours d'utilisation.
OriginalL'auteur Joonas Pulakka
Ce que vous pouvez faire est de mettre en œuvre la
Iterator
interface vous-même (si vous avez besoin de faire l'interface avec d'autres API) et demandez à vos clients de mettre en œuvre vos propres plus strictes de l'interface.J'ai créé une classe de ce type dans ma fonctionnelle de la programmation de la bibliothèque afin d'implémenter facilement un
Iterator
autour d'unResultSet
dans un projet au travail.Ma classe EasierIterator implémente l'interface Iterator tout en exigeant que le client implémente une interface simple basée sur
moveNext()
/getCurrent()
. C'est en fait la mise en cache de l'élément en cours pour vous.Current
etMoveNext
, la Java de l'interface iterator a été me rend fou à essayer de comprendre comment sainement traiter avec les itérateurs où la seule chose que vous pouvez faire est de "get next ou nul". Je ne suis pas sûr de savoir comment Java fini avec cettehasNext
etnext
interface, il semble qu'il n'a de sens trivial types comme en mémoire des tableaux où jeter un oeil à l'élément suivant est un bon et reproductible de l'opération.OriginalL'auteur Vincent Robert
Que vous pourriez faire quelque chose de similaire à ci-dessous, permettant de déléguer les données sous-jacentes extraction d'une méthode privée, et de mettre en œuvre
hasNext()
etnext()
de réagir différemment à l'absence de données. Ceci a l'avantage que vous pouvez appeler à plusieurs reprisesnext()
sans appelhasNext()
premier, et donc de ne pas violer le contrat de Itérateur.L'utilisation de la volatilité pourrait pas en phase avec la question, car il a été précisé que ne sont accessibles que par un seul thread, est-il une autre raison pour laquelle il est utilisé ici? Aussi, dans tryGetNext(), puisque l'opération dépend de la valeur de la prochaine, ne faut-il pas AtomicReferenceFieldUpdater être utilisé?
D'accord - je ne sais pas pourquoi j'ai écrit ça comme ça car c'est clairement pas thread-safe, même avec des volatiles; il y a du potentiel pour les 2 threads à la fois d'à côté et les deux finissent par appeler la source.poll(). Je vais modifier pour la rendre pleinement thread-safe.
OriginalL'auteur Adamski
EDIT: Dans cette réponse, j'ai essayé d'argumenter qu'il est admis que la question demande. Mais j'ai oublié une phrase de la
Iterator.hasNext
documentation qui invalide tout mon raisonnement:Cela semble impliquer que l'appel
next
à plusieurs reprises jusqu'à ce quehasNext
retourne true et l'appel suivant jusqu'à ce que vous obtenez uneNoSuchElementException
doit retourner la même séquence d'éléments.Ainsi, il semble que ce que la question demande est pas permis.
Réponse originale à cette question
C'est une tentative sur un cahier des charges avocat type de réponse. Pour plus de clarté, je vais reformuler la question dans une forme compacte:
Discussion
La documentation pour
Itérateur.hasNext
états:Et pour
Itérateur.suivant
:Apparemment, il est permis de jeter à la
NoSuchElementException
lorsque "l'itération n'a pas plus d'éléments", mais pas avant que. Qui devrait coïncider avec le moment oùhasNext
renvoie la valeur false.Cela conduit à la question: Exactement ce que la documentation veux dire avec "l'itération" et "éléments"? Le
Iterator
de la documentation ne permet pas de donner une réponse à cette question, ce qui donne une certaine agitation de l'espace pour les exécutants.De mon point de vue il y a deux interprétations possibles:
Du point de vue de l'interface iterator lui-même le concept de "itération" est "aussi longtemps que
hasNext
retourne true". Cela implique que si le client appellenext
avanthasNext
ils ne savent pas si il y a plus d'éléments, il est indéfini.Il est donc autorisé par le cahier des charges pour l'itérateur responsable de l'implémentation de décider que l'itération est terminée. Donc la réponse à la question est oui.
Mais la documentation sur
Itératif.iterator
également mention des "éléments":Donc, ce n'est "éléments"? Signifie-t-il "tous les éléments dans la collection de la mise en œuvre de
Iterable
? Non, il ne le dit pas, et pas tous les iterables même ont un ensemble fixe d'éléments.Ce sont des "éléments" signifie pour certains itérable est à gauche de l'opérateur de décider. Une définition valable de la "éléments" pour un itérateur peut être "tous les éléments de la collection, OU, tous les éléments avant que le client décide d'appeler
next
avanthasNext
".Donc ce cas également conduit à la conclusion que la réponse à la question est oui. (Mais s'il vous plaît voir la note sur la fin!)
Conclution
La documentation n'est pas vraiment clair, mais il semble que la réponse à la question est: Oui, cela est permis.
Note
Dans le cas où un itérateur n'est que la question porte sur le comportement devrait être documenté, bien sûr. Mais d'autres iterables doit également documenter les éléments de leur itérateurs sont.
Par exemple, la
ArrayList.iterator
documentation indique clairement qui éléments de l'itérateur est sur:note Finale: Oui, je suis fou de passer autant de temps sur ce.
hasNext
est clairement conçu comme un non-mutation de méthode qui se contente d'interroger le statut de "nous avons un autre élément" et les deux "hasNext()
retourne false" et "next()
jette unNoSuchElementException
" sont définies en utilisant la même formulation. Si vous avez besoin d'une classe qui se comporte de la façon la question décrit très bien, mais je pense faire de la mettre en œuvreIterator
est une erreur.Il pourrait être une erreur. Je suis d'accord que c'est assez bizarre. Dans cette réponse, j'ai essayer de voir à partir d'une spécification de la couche de point de vue ici.
D'autre part,
next
est clairement destinée à être appelée avanthasNext
, de sorte que le client est le genre de spectacle undefined opérations et doivent s'attendre à un comportement inattendu. La question est: Combien de problèmes supplémentaires dois-je faire pour moi-même lors de la mise en œuvre de mes itérateur afin de soutenir ce comportement bizarre par les clients, au lieu de créer un système plus simple mais un peu bizarre itérateur?Je suis d'accord que tout cela est des règles juridiques, mais je vais continuer: oui.
hasNext
est signifie pour être appelée avantnext
, je suis d'accord avec ça (juste parce que la capture de évitables exceptions est une odeur de code). Cependant, il est pas comportement indéfini à utiliser uniquementnext
sur un Itérateur: si retournera toutes les valeurs et de jeter unNoSuchElementException
sur le prochain appel. Il y a même un certain blocage "infini"Iterator
implémentations qui renvoient toujourstrue
dehasNext
et il suffit de le bloquer surnext
lorsque l'élément suivant n'est pas encore disponible. Aussi laid, mais techniquement valides.Hm. J'ai maintenant remarqué une autre phrase dans le
hasNext
la documentation dont j'ai oublié avant: "En d'autres termes, retourne vrai sinext()
serait de retour d'un élément plutôt que de lancer une exception." en fait, Cela semble être le soutien direct de votre position dans la documentation. Elle semble sous-entendre que l'appelnext
jusqu'àhasNext
renvoie true, et appelantnext
jusqu'à ce que vous obtenez uneNoSuchElementException
doit retourner la même séquence d'éléments.OriginalL'auteur Lii