java - Iterating over a two level structure using nested iterators -
i have following 2 level xml
structure. list of boxes, each containing list of drawers.
<boxes> <box id="0"> <drawers> <drawer id="0"/> <drawer id="1"/> ... </drawers> </box> <box id="1"> ... </box> </boxes>
i'm parsing using stax
, exposed structure through 2 iterators
:
boxiterator implements iterator<box>, iterable<box>
box implements iterable<drawer>
draweriterator implements iterator<drawer>
i can following:
boxiterator boxlist; (box box : boxlist) { (drawer drawer : box) { drawer.getid() } }
under hood of iterators
i'm using stax
, both of them accessing same underlying xmlstreamreader
. if call boxiterator.next()
influence result returned on subsequent calls draweriterator.next()
because cursor have moved next box.
does break contract of iterator
? there better way iterate on 2 level structure using stax
?
does break contract of
iterator
?
no.
the java iterator
imposes 2 "contracts". first contract java interface itself, declares 3 methods: hasnext()
, next()
, , remove()
. class implements iterator
interface must define methods.
the second contract defines behaviour of iterator
:
hasnext()
[...] returns true if iteration has more elements. [...]next()
returns next element in iteration [and] throwsnosuchelementexception
if iteration has no more elements.
that entire contract.
it true if underlying xmlstreamreader
advanced, can mess boxiterator
and/or draweriterator
. alternately, calling boxiterator.next()
and/or draweriterator.next()
@ wrong points mess iteration. however, used correctly, such in example code above, works , simplifies code. need document proper usage of iterators.
as concrete example, scanner
class implements iterator<string>
, , yet has many, many other methods advance underlying stream. if there existed stronger contract imposed iterator
class, scanner
class violating it.
as ivan points out in comments, boxlist
should not of type class boxiterator implements iterator<box>, iterable<box>
. should have:
class boxlist implements iterable<box> { ... } class boxiterator implements iterator<box> { ... } boxlist boxlist = ...; (box box : boxlist) { (drawer drawer : box) { drawer.getid() } }
while having 1 class implement both iterable
, iterator
not technically wrong for use case, can cause confusion.
consider code in context:
list<box> boxlist = arrays.aslist(box1, box2, box3, box4); for(box box : boxlist) { // } for(box box : boxlist) { // more stuff }
here, boxlist.iterator()
called twice, create 2 separate iterator<box>
instances, iterating list of boxes twice. because boxlist
can iterated on multiple times, each iteration requires new iterator instance.
in code:
boxiterator boxlist = new boxiterator(xml_stream); (box box : boxlist) { (drawer drawer : box) { drawer.getid(); } }
because iterating on stream, can't (without rewinding stream, or storing extracted objects) iterate on same nodes second time. second class/object not needed; same object can act both iterable , iterator ... saves 1 class/object.
having said that, premature optimization root of evil. savings of 1 class/object not worth possible confusion; should split boxiterator
boxlist implements iterable<box>
, , boxiterator implements iterator<box>
.
Comments
Post a Comment