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:

  1. boxiterator implements iterator<box>, iterable<box>
  2. box implements iterable<drawer>
  3. 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] throws nosuchelementexception 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

Popular posts from this blog

magento2 - Magento 2 admin grid add filter to collection -

Android volley - avoid multiple requests of the same kind to the server? -

Combining PHP Registration and Login into one class with multiple functions in one PHP file -