1
2
3 package eu.simuline.util;
4
5
6 import java.util.List;
7 import java.util.ArrayList;
8 import java.util.Set;
9 import java.util.SortedSet;
10 import java.util.AbstractSet;
11 import java.util.Collection;
12 import java.util.AbstractCollection;
13 import java.util.SortedMap;
14 import java.util.Map;
15 import java.util.Map.Entry;
16 import java.util.Comparator;
17 import java.util.Iterator;
18 import java.util.ListIterator;
19 import java.util.Objects;
20
21 /**
22 * A {@link SortedMap} with ordering
23 * given by the ordering by which the keys are added.
24 * This is the {@link Map} corresponding with {@link ListSet}.
25 * <p>
26 * Did not use {@link java.util.AbstractMap},
27 * e.g. because {@link #keySet()} shall return more than just a {@link Set}.
28 *
29 * @param <K>
30 * the class of keys for this map.
31 * @param <V>
32 * the class of values for this map.
33 *
34 * @author <a href="mailto:ernst.reissner@simuline.eu">Ernst Reissner</a>
35 * @version 1.0
36 */
37 public final class ListMap<K, V> implements SortedMap<K, V> {
38
39 /* -------------------------------------------------------------------- *
40 * Inner classes. *
41 * -------------------------------------------------------------------- */
42
43 /**
44 * Class of entries of the encylosing map.
45 * **** I wonder whether there is no generic implementation
46 * for {@link java.util.Map.Entry}.
47 */
48 private final class Entry implements Map.Entry<K, V> {
49
50 /* ------------------------------------------------------------------ *
51 * fields. *
52 * ------------------------------------------------------------------ */
53
54 /**
55 * The key of this entry.
56 * The corresponding value is {@link #value}.
57 */
58 private final K key;
59
60 /**
61 * The value of this entry corresponding with the key {@link #key}.
62 * Note that in contrast to the key,
63 * the value of this entry may be changed
64 * (through {@link #setValue(Object)}).
65 */
66 private V value;
67
68 /* ------------------------------------------------------------------ *
69 * constructors. *
70 * ------------------------------------------------------------------ */
71
72 /**
73 * Creates a new entry for the enclosing map
74 * defined by the given <code>key</code> and <code>value</code>.
75 */
76 private Entry(K key, V value) {
77 this.key = key;
78 this.value = value;
79 }
80
81 /* ------------------------------------------------------------------ *
82 * methods. *
83 * ------------------------------------------------------------------ */
84
85 /**
86 * Returns the {@link #key} of this entry.
87 */
88 public K getKey() {
89 return this.key;
90 }
91
92 /**
93 * Returns the {@link #value} of this entry.
94 */
95 public V getValue() {
96 return this.value;
97 }
98
99 /**
100 * Sets a new {@link #value} of this entry
101 * and returns the original one.
102 */
103 public V setValue(V value) {
104 V oldValue = this.value;
105 this.value = value;
106 return oldValue;
107 }
108
109 // fits with method equals
110 public int hashCode() {
111 return this.getKey().hashCode() + this.getValue().hashCode();
112 }
113
114 // **** seems to be a bug in javadoc
115 /**
116 * Returns whether <code>obj</code> equals this entry,
117 * i.e. whether <code>obj</code>
118 * is an instance of {@link java.util.Map.Entry}
119 * and both, its key and its value equals key and value of this entry.
120 * Note that both, key and value may be <code>null</code>.
121 */
122 public boolean equals(Object obj) {
123 if (!(obj instanceof Map.Entry)) {
124 return false;
125 }
126
127 Map.Entry<?, ?> other = (Map.Entry<?, ?>) obj;
128 return Objects.equals(this.getKey(), other.getKey())
129 && Objects.equals(this.getValue(), other.getValue());
130 }
131
132 } // class Entry
133
134 /**
135 * Represents the key set of the enclosing map
136 * given by {@link ListMap#keySet()}.
137 * <p>
138 * Like base class {@link AbstractSet},
139 * this class supports neither {@link Set#add(Object)}
140 * nor {@link Set#addAll(Collection)},
141 * i.e. those methods throw an {@link UnsupportedOperationException}.
142 * In contrast, this class supports methods
143 * {@link Set#clear()},
144 * {@link Set#remove(Object)},
145 * {@link Set#removeAll(Collection)} and
146 * {@link Set#retainAll(Collection)}.
147 * The iterator returned by {@link #iterator()}
148 * supports {@link Iterator#remove()}.
149 *
150 * @see ListMap#keysSet
151 */
152 private class Keys extends AbstractSet<K> implements SortedSet<K> {
153
154 /* ------------------------------------------------------------------ *
155 * methods implementing Set based on AbstractSet. *
156 * ------------------------------------------------------------------ */
157
158 /**
159 * Returns actually an instance of {@link ListMap.KeysIterator}.
160 */
161 public Iterator<K> iterator() {
162 return new KeysIterator();
163 }
164
165 /**
166 * Returns actually the size of the enclosing {@link ListMap}
167 * delegating to {@link ListMap#size()}.
168 */
169 public int size() {
170 return ListMap.this.size();
171 }
172
173 /**
174 * Returns actually whether <code>obj</code>
175 * is a key of the enclosing {@link ListMap}
176 * delegating to {@link ListMap#containsKey(Object)}.
177 */
178 public boolean contains(Object obj) {
179 return ListMap.this.containsKey(obj);
180 }
181
182 /**
183 * Interpretes <code>obj</code> as key
184 * of the enclosing {@link ListMap}
185 * and removes the according key-value pair if present.
186 * Returns whether the according key-value pair was present
187 * when invoking this method using
188 * {@link ListMap#removeIdx(int)}.
189 */
190 public boolean remove(Object obj) {
191 int idx = ListMap.this.keys.getList().indexOf(obj);
192 return ListMap.this.removeIdx(idx);
193 }
194
195 /**
196 * Clears actually the enclosing {@link ListMap}
197 * delegating to {@link ListMap#clear()}.
198 */
199 public void clear() {
200 ListMap.this.clear();
201 }
202
203 /* ------------------------------------------------------------------ *
204 * methods implementing SortedSet. *
205 * ------------------------------------------------------------------ */
206
207 public Comparator<? super K> comparator() {
208 return ListMap.this.comparator();
209 }
210
211 public K first() {
212 return ListMap.this.keys.first();
213 }
214
215 public K last() {
216 return ListMap.this.keys.last();
217 }
218
219 public SortedSet<K> subSet(K fromElement, K toElement) {
220 return ListMap.this.subMap(fromElement, toElement).keySet();
221 }
222
223 public SortedSet<K> headSet(K toElement) {
224 return ListMap.this.headMap(toElement).keySet();
225 }
226
227 public SortedSet<K> tailSet(K fromElement) {
228 return ListMap.this.tailMap(fromElement).keySet();
229 }
230
231 } // class Keys
232
233 /**
234 * Class of iterator of class {@link ListMap.Keys}.
235 *
236 * @see ListMap.Keys#iterator()
237 */
238 private class KeysIterator extends XIterator implements Iterator<K> {
239 public K next() {
240 return this.lIter.next();
241 }
242 } // class KeysIterator
243
244
245 /**
246 * Represents the set of entries of the enclosing map
247 * given by {@link ListMap#entrySet()}.
248 * <p>
249 * Like base class {@link AbstractSet},
250 * this class supports neither {@link Set#add(Object)}
251 * nor {@link Set#addAll(Collection)},
252 * i.e. those methods throw an {@link UnsupportedOperationException}.
253 * In contrast, this class supports methods
254 * {@link Set#clear()},
255 * {@link Set#remove(Object)},
256 * {@link Set#removeAll(Collection)} and
257 * {@link Set#retainAll(Collection)}.
258 * The iterator returned by {@link #iterator()}
259 * supports {@link Iterator#remove()}.
260 *
261 * @see ListMap#entrySet
262 */
263 private class Entries
264 extends AbstractSet<Map.Entry<K, V>>
265 implements SortedSet<Map.Entry<K, V>> {
266
267 /* ------------------------------------------------------------------ *
268 * methods implementing Set based on AbstractSet. *
269 * ------------------------------------------------------------------ */
270
271 /**
272 * Returns actually an instance of {@link ListMap.EntriesIterator}.
273 */
274 public Iterator<Map.Entry<K, V>> iterator() {
275 return new EntriesIterator();
276 }
277
278 /**
279 * Returns actually the size of the enclosing {@link ListMap}
280 * delegating to {@link ListMap#size()}.
281 */
282 public int size() {
283 return ListMap.this.size();
284 }
285
286 /**
287 * Assumes that <code>obj</code> is a {@link java.util.Map.Entry}
288 * and returns its key.
289 *
290 * @throws NullPointerException
291 * if <code>obj</code> is <code>null</code>.
292 * @throws ClassCastException
293 * if <code>obj</code> is neither <code>null</code>
294 * nor an instance of {@link java.util.Map.Entry}.
295 */
296 private Object getKey(Object obj) {
297 Map.Entry<?, ?> entry = (Map.Entry<?, ?>) obj;
298 return entry.getKey();
299 }
300
301 /**
302 * Returns actually whether <code>obj</code>
303 * is an instance of {@link java.util.Map.Entry}
304 * with a key contained in the enclosing {@link ListMap}
305 * delegating to {@link ListMap#containsKey(Object)}.
306 */
307 public boolean contains(Object obj) {
308 if (!(obj instanceof Map.Entry)) {
309 return false;
310 }
311 return ListMap.this.containsKey(getKey(obj));
312 }
313
314 /**
315 * Removes <code>obj</code> from the entry set if present
316 * and returns whether it was present.
317 * Effectively checks whether <code>obj</code>
318 * is an instance of {@link java.util.Map.Entry}.
319 * If not returns <code>false</code>.
320 * If it is an instance of {@link java.util.Map.Entry}
321 * removes the according key-value pair
322 * from the enclosing {@link ListMap} if present.
323 * Returns whether <code>obj</code>'s key was present
324 * when invoking this method.
325 * This is done
326 * invoking {@link ListMap.Keys#remove(Object)}.
327 */
328 public boolean remove(Object obj) {
329 if (!(obj instanceof Map.Entry)) {
330 return false;
331 }
332 Map.Entry<?, ?> entry = (Map.Entry<?, ?>) obj;
333 entry.getClass().getTypeParameters();
334 return ListMap.this.keysSet.remove(getKey(entry));
335 }
336
337 /**
338 * Clears actually the enclosing {@link ListMap}
339 * delegating to {@link ListMap#clear()}.
340 */
341 public void clear() {
342 ListMap.this.clear();
343 }
344
345 /* ------------------------------------------------------------------ *
346 * methods implementing SortedSet. *
347 * ------------------------------------------------------------------ */
348
349 public Comparator<? super Map.Entry<K, V>> comparator() {
350 return new Comparator<Map.Entry<K, V>>() {
351 public int compare(Map.Entry<K, V> entry1,
352 Map.Entry<K, V> entry2) {
353 return ListMap.this.comparator()
354 .compare(entry1.getKey(), entry2.getKey());
355 }
356 };
357 }
358
359 private Map.Entry<K, V> key2entry(K key) {
360 return new ListMap<K, V>.Entry(key, get(key));
361 }
362
363 public Map.Entry<K, V> first() {
364 return key2entry(ListMap.this.keys.first());
365 }
366
367 public Map.Entry<K, V> last() {
368 return key2entry(ListMap.this.keys.last());
369 }
370
371 public SortedSet<Map.Entry<K, V>> subSet(Map.Entry<K, V> fromElement,
372 Map.Entry<K, V> toElement) {
373 return ListMap.this.subMap(fromElement.getKey(),
374 toElement .getKey()).entrySet();
375 }
376
377 public SortedSet<Map.Entry<K, V>> headSet(Map.Entry<K, V> toElement) {
378 return ListMap.this.headMap(toElement .getKey()).entrySet();
379 }
380
381 public SortedSet<Map.Entry<K, V>> tailSet(Map.Entry<K, V> fromElement) {
382 return ListMap.this.tailMap(fromElement.getKey()).entrySet();
383 }
384
385 } // class Entries
386
387 /**
388 * Class of iterator of class {@link ListMap.Entries}.
389 *
390 * @see ListMap.Entries#iterator()
391 */
392 private class EntriesIterator extends XIterator
393 implements Iterator<Map.Entry<K, V>> {
394
395 public Map.Entry<K, V> next() {
396 int idx = this.lIter.nextIndex();
397 return new Entry(this.lIter.next(),
398 ListMap.this.values.get(idx));
399 }
400 } // class EntriesIterator
401
402 /**
403 * Represents the values collection of the enclosing map
404 * given by {@link ListMap#values()}.
405 * <p>
406 * Like base class {@link AbstractCollection},
407 * this class supports neither {@link Collection#add(Object)}
408 * nor {@link Collection#addAll(Collection)},
409 * i.e. those methods throw an {@link UnsupportedOperationException}.
410 * In contrast, this class supports methods
411 * {@link Set#clear()},
412 * {@link Collection#remove(Object)},
413 * {@link Collection#removeAll(Collection)} and
414 * {@link Collection#retainAll(Collection)}.
415 * The iterator returned by {@link #iterator()}
416 * supports @link Iterator#remove()}.
417 *
418 * @see ListMap#valuesColl
419 */
420 private class Values extends AbstractCollection<V> {
421
422 /**
423 * Returns actually an instance of {@link ListMap.ValuesIterator}.
424 */
425 public Iterator<V> iterator() {
426 return new ValuesIterator();
427 }
428
429 /**
430 * Returns actually the size of the enclosing {@link ListMap}
431 * delegating to {@link ListMap#size()}.
432 */
433 public int size() {
434 return ListMap.this.size();
435 }
436
437 /**
438 * Returns actually whether <code>obj</code>
439 * is a value of the enclosing {@link ListMap}
440 * delegating to {@link ListMap#containsValue(Object)}.
441 */
442 public boolean contains(Object obj) {
443 return ListMap.this.containsValue(obj);
444 }
445
446 /**
447 * Interpretes <code>obj</code> as value
448 * of the enclosing {@link ListMap}
449 * and removes the first according key-value pair if present.
450 * Returns whether the according key-value pair was present
451 * when invoking this method invoking using
452 * {@link ListMap#removeIdx(int)}.
453 */
454 public boolean remove(Object obj) {
455 int idx = ListMap.this.values.indexOf(obj);
456 return ListMap.this.removeIdx(idx);
457 }
458
459 /**
460 * Clears actually the enclosing {@link ListMap}
461 * delegating to {@link ListMap#clear()}.
462 */
463 public void clear() {
464 ListMap.this.clear();
465 }
466
467 } // class Values
468
469 /**
470 * Class of iterator of class {@link ListMap.Values}.
471 *
472 * @see ListMap.Values#iterator()
473 */
474 @edu.umd.cs.findbugs.annotations.SuppressWarnings
475 (value = "RV_RETURN_VALUE_IGNORED_NO_SIDE_EFFECT",
476 justification = "bug in findbugs")
477 private class ValuesIterator extends XIterator implements Iterator<V> {
478 public V next() {
479 int idx = this.lIter.nextIndex();
480 this.lIter.next(); // has side effect!
481 return ListMap.this.values.get(idx);
482 }
483 } // class ValuesIterator
484
485 /**
486 * Common superclass of iterators on key set,
487 * value collection and entries set
488 * providing all methods but {@link Iterator#next()}.
489 * Implementation is based on a {@link ListIterator}.
490 */
491 private abstract class XIterator {
492
493 /* ------------------------------------------------------------------ *
494 * fields. *
495 * ------------------------------------------------------------------ */
496
497 /**
498 * An iterator over the list view of the key set
499 * of the enclosing {@link ListMap}.
500 *
501 * @see ListMap#keys
502 * @see ListSet#getList()
503 */
504 @SuppressWarnings("checkstyle:visibilitymodifier")
505 protected final ListIterator<K> lIter;
506
507 /* ------------------------------------------------------------------ *
508 * constructors. *
509 * ------------------------------------------------------------------ */
510
511 /**
512 * Creates a pre-iterator.
513 *
514 * @see ListMap#keys
515 * @see ListSet#getList()
516 */
517 XIterator() {
518 this.lIter = ListMap.this.keys.getList().listIterator();
519 }
520
521 /* ------------------------------------------------------------------ *
522 * methods. *
523 * ------------------------------------------------------------------ */
524
525 /**
526 * Returns whether the iterators based on this class
527 * has a next value.
528 *
529 * @see Iterator#hasNext()
530 */
531 public boolean hasNext() {
532 return this.lIter.hasNext();
533 }
534 //public abstract X next();
535
536 /**
537 * Removes from the underlying collection the last element returned
538 * by the iterator based on this class.
539 *
540 * @see Iterator#remove()
541 */
542 public void remove() {
543 // get the index of the element returned by next() last
544 int idxPrev = this.lIter.previousIndex();
545 if (idxPrev == -1) {
546 // never called next()
547 throw new IllegalStateException();
548 }
549 ListMap.this.removeIdx(idxPrev);
550 }
551 } // class XIterator
552
553 /* -------------------------------------------------------------------- *
554 * fields. *
555 * -------------------------------------------------------------------- */
556
557 /**
558 * The set of keys of this <code>ListMap</code>.
559 */
560 private final ListSet<K> keys;
561
562 /**
563 * The values of this map.
564 * The according keys are in {@link #keys}.
565 */
566 private final List<V> values;
567
568 /**
569 * The collection of values of this map returned by {@link #values()}.
570 * Note that each <code>ListMap</code> has a single values collection.
571 */
572 private final Collection<V> valuesColl;
573
574 /**
575 * The set of keys of this map returned by {@link #keySet()}.
576 * Note that each <code>ListMap</code> has a single key set.
577 */
578 private final SortedSet<K> keysSet;
579
580 /**
581 * The set of entries of this map returned by {@link #entrySet()}.
582 * Note that each <code>ListMap</code> has a single entry set.
583 */
584 private final SortedSet<Map.Entry<K, V>> entrySet;
585
586 /* -------------------------------------------------------------------- *
587 * constructors and auxiliary methods. *
588 * -------------------------------------------------------------------- */
589
590 /**
591 * Creates an empty list map with key set 'ordered as added'
592 * as described by {@link ListSet#sortedAsAdded()}.
593 */
594 public ListMap() {
595 this(ListSet.sortedAsAdded(), new ArrayList<V>());
596 }
597
598 /**
599 * Creates an list map with the same key-value pairs as <code>map</code>
600 * and with ordering 'as added'.
601 * If no additional keys are added, this reflects the ordering
602 * given by iterating through the key set of <code>map</code>.
603 *
604 * @see #map2keys(Map)
605 * @see #map2values(Map)
606 */
607 public ListMap(Map<K, V> map) {
608 this(map2keys(map), map2values(map));
609 }
610
611 /**
612 * Returns the key set of <code>map</code> as a <code>ListSet</code>
613 * with ordering 'ordered as added'
614 * as given by {@link ListSet#sortedAsAdded()}.
615 * This ordering reflects the ordering
616 * given by the iteration on the key set of <code>map</code>.
617 */
618 private static <K, V> ListSet<K> map2keys(Map<K, V> map) {
619 ListSet<K> res = ListSet.sortedAsAdded();
620 res.addAll(map.keySet());
621 return res;
622 }
623
624 /**
625 * Returns the value collection of <code>map</code> as a <code>List</code>
626 * with ordering
627 * given by the iteration on the key set of <code>map</code>.
628 * Note that there is no documentation ****
629 * that this ordering is the same as the one
630 * of the value collection {@link Map#values() map#values()}. ****
631 */
632 private static <K, V> List<V> map2values(Map<K, V> map) {
633 List<V> res = new ArrayList<V>();
634 // **** using entrySet() would be more elegant,
635 // but seems not to guarantee an ordering of iteration.
636 for (K key : map.keySet()) {
637 res.add(map.get(key));
638 }
639 return res;
640 }
641
642 /**
643 * Creates a list map defined by the given keys and values
644 * <code>keys</code> and <code>values</code>.
645 * A key and a value correspond iff their index coincides.
646 * Thus <code>keys</code> and <code>values</code> must have the same size.
647 * Note that the entries of <code>keys</code> differ pairwise,
648 * whereas this is not necessary for <code>values</code>.
649 *
650 * @param keys
651 * the set of keys as a {@link ListSet}.
652 * @param values
653 * the collection of according values as a {@link List}
654 * with the same size as <code>keys</code>.
655 * @throws IllegalArgumentException
656 * if <code>keys</code> and <code>values</code> differ in size.
657 */
658 private ListMap(ListSet<K> keys, List<V> values) {
659 if (keys.size() != values.size()) {
660 throw new IllegalArgumentException
661 ("Collection of keys and values must have same size. ");
662 }
663
664 this.keys = keys;
665 this.values = values;
666 this.valuesColl = new Values();
667 this.keysSet = new Keys();
668 this.entrySet = new Entries();
669 }
670
671 /* -------------------------------------------------------------------- *
672 * Methods. *
673 * -------------------------------------------------------------------- */
674
675 public void clear() {
676 this.keys .clear();
677 this.values.clear();
678 }
679
680 public boolean containsKey(Object key) {
681 return this.keys.contains(key);
682 }
683
684 public boolean containsValue(Object val) {
685 return this.values.contains(val);
686 }
687
688 public SortedSet<Map.Entry<K, V>> entrySet() {
689 return this.entrySet;
690 }
691
692 public V get(Object key) {
693 int idx = this.keys.getList().indexOf(key);
694 if (idx == -1) {
695 return null;
696 }
697 assert idx >= 0 && idx < size();
698 return this.values.get(idx);
699 }
700
701 public boolean isEmpty() {
702 assert this.keys.isEmpty() == this.values.isEmpty();
703 return this.keys.isEmpty();
704 }
705
706 public SortedSet<K> keySet() {
707 return this.keysSet;
708 }
709
710 public V put(K key, V value) {
711 int idx = this.keys.getList().indexOf(key);
712 if (idx == -1) {
713 // Here, key is to be added
714 this.keys.getList().add(key);
715 this.values.add(value);
716 return null;
717 }
718 assert idx >= 0 && idx < size();
719
720 return this.values.set(idx, value);
721 }
722
723 public void putAll(Map<? extends K, ? extends V> other) {
724 Iterator<? extends K> iter = other.keySet().iterator();
725 K key;
726 while (iter.hasNext()) {
727 key = iter.next();
728 this.put(key, other.get(key));
729 }
730 }
731
732 public V remove(Object key) {
733 int idx = this.keys.getList().indexOf(key);
734 if (idx == -1) {
735 return null;
736 }
737 assert idx >= 0 && idx < size();
738 V res = this.values.get(idx);
739 this.keys.getList().remove(idx);
740 this.values.remove(idx);
741 return res;
742 }
743
744 private boolean removeIdx(int idx) {
745 if (idx == -1) {
746 return false;
747 }
748 assert idx >= 0 && idx < size();
749 this.keys.getList().remove(idx);
750 this.values.remove(idx);
751 return true;
752 }
753
754 public int size() {
755 return this.keys.size();
756 }
757
758 public Comparator<? super K> comparator() {
759 return this.keys.comparator();
760 }
761
762 public Collection<V> values() {
763 return this.valuesColl;
764 }
765
766 // also throws correct exception
767 public K firstKey() {
768 return keySet().first();
769 }
770
771 // also throws correct exception
772 public K lastKey() {
773 return keySet().last();
774 }
775
776 // better removed because easy to mix up with other methods
777 // offering just a view, not a copy of part of this map
778 // public Map<K,V> subMap(Set<K> someKeys) {
779 // V val;
780 // ListMap<K, V> res = new ListMap<K, V>();
781 // for (K key : someKeys) {
782 // val = get(key);
783 // res.put(key, val);
784 // }
785 // return res;
786 // }
787
788 public ListMap<K, V> headMap(K toKey) {
789 return subMap(0, this.keys.obj2idx(toKey));
790 }
791
792 public ListMap<K, V> tailMap(K fromKey) {
793 return subMap(this.keys.obj2idx(fromKey), size());
794 }
795
796
797 @SuppressWarnings("checkstyle:genericwhitespace")
798 ListMap<K, V> subMap(int fromIdx, int toIdx) {
799 ListSet<K> subKeys = this.keys .subSetIdx(fromIdx, toIdx);
800 List <V> subValues = this.values.subList (fromIdx, toIdx);
801
802 return new ListMap<K, V>(subKeys, subValues);
803 }
804
805 public ListMap<K, V> subMap(K fromKey, K toKey) {
806 return subMap(this.keys.obj2idx(fromKey), this.keys.obj2idx(toKey));
807 }
808
809 public boolean equals(Object obj) {
810 if (!(obj instanceof Map)) {
811 return false;
812 }
813
814 Map<?, ?> other = (Map<?, ?>) obj;
815 return this.entrySet().equals(other.entrySet());
816 }
817
818 public int hashCode() {
819 return this.entrySet().hashCode();
820 }
821
822 public String toString() {
823 StringBuffer result = new StringBuffer();
824 result.append("<ListMap>\n");
825 for (int i = 0; i < size(); i++) {
826 result.append("[" + this.keys.getList().get(i)
827 + " => " + this.values.get(i) + "]\n");
828 }
829 result.append("</ListMap>\n");
830
831 return result.toString();
832 }
833
834 public static void main(String[] args) {
835 List<Integer> list = new ArrayList<Integer>();
836 //list.add(0);
837 list.iterator().remove();
838 }
839 }