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 // PMD: rethink AbstractClassWithoutAbstractMethod
492 private abstract class XIterator {// NOPMD
493
494 /* ------------------------------------------------------------------ *
495 * fields. *
496 * ------------------------------------------------------------------ */
497
498 /**
499 * An iterator over the list view of the key set
500 * of the enclosing {@link ListMap}.
501 *
502 * @see ListMap#keys
503 * @see ListSet#getList()
504 */
505 @SuppressWarnings("checkstyle:visibilitymodifier")
506 protected final ListIterator<K> lIter;
507
508 /* ------------------------------------------------------------------ *
509 * constructors. *
510 * ------------------------------------------------------------------ */
511
512 /**
513 * Creates a pre-iterator.
514 *
515 * @see ListMap#keys
516 * @see ListSet#getList()
517 */
518 XIterator() {
519 this.lIter = ListMap.this.keys.getList().listIterator();
520 }
521
522 /* ------------------------------------------------------------------ *
523 * methods. *
524 * ------------------------------------------------------------------ */
525
526 /**
527 * Returns whether the iterators based on this class
528 * has a next value.
529 *
530 * @see Iterator#hasNext()
531 */
532 public boolean hasNext() {
533 return this.lIter.hasNext();
534 }
535 //public abstract X next();
536
537 /**
538 * Removes from the underlying collection the last element returned
539 * by the iterator based on this class.
540 *
541 * @see Iterator#remove()
542 */
543 public void remove() {
544 // get the index of the element returned by next() last
545 int idxPrev = this.lIter.previousIndex();
546 if (idxPrev == -1) {
547 // never called next()
548 throw new IllegalStateException();
549 }
550 ListMap.this.removeIdx(idxPrev);
551 }
552 } // class XIterator
553
554 /* -------------------------------------------------------------------- *
555 * fields. *
556 * -------------------------------------------------------------------- */
557
558 /**
559 * The set of keys of this <code>ListMap</code>.
560 */
561 private final ListSet<K> keys;
562
563 /**
564 * The values of this map.
565 * The according keys are in {@link #keys}.
566 */
567 private final List<V> values;
568
569 /**
570 * The collection of values of this map returned by {@link #values()}.
571 * Note that each <code>ListMap</code> has a single values collection.
572 */
573 private final Collection<V> valuesColl;
574
575 /**
576 * The set of keys of this map returned by {@link #keySet()}.
577 * Note that each <code>ListMap</code> has a single key set.
578 */
579 private final SortedSet<K> keysSet;
580
581 /**
582 * The set of entries of this map returned by {@link #entrySet()}.
583 * Note that each <code>ListMap</code> has a single entry set.
584 */
585 private final SortedSet<Map.Entry<K, V>> entrySet;
586
587 /* -------------------------------------------------------------------- *
588 * constructors and auxiliary methods. *
589 * -------------------------------------------------------------------- */
590
591 /**
592 * Creates an empty list map with key set 'ordered as added'
593 * as described by {@link ListSet#sortedAsAdded()}.
594 */
595 public ListMap() {
596 this(ListSet.sortedAsAdded(), new ArrayList<V>());
597 }
598
599 /**
600 * Creates an list map with the same key-value pairs as <code>map</code>
601 * and with ordering 'as added'.
602 * If no additional keys are added, this reflects the ordering
603 * given by iterating through the key set of <code>map</code>.
604 *
605 * @see #map2keys(Map)
606 * @see #map2values(Map)
607 */
608 public ListMap(Map<K, V> map) {
609 this(map2keys(map), map2values(map));
610 }
611
612 /**
613 * Returns the key set of <code>map</code> as a <code>ListSet</code>
614 * with ordering 'ordered as added'
615 * as given by {@link ListSet#sortedAsAdded()}.
616 * This ordering reflects the ordering
617 * given by the iteration on the key set of <code>map</code>.
618 */
619 private static <K, V> ListSet<K> map2keys(Map<K, V> map) {
620 ListSet<K> res = ListSet.sortedAsAdded();
621 res.addAll(map.keySet());
622 return res;
623 }
624
625 /**
626 * Returns the value collection of <code>map</code> as a <code>List</code>
627 * with ordering
628 * given by the iteration on the key set of <code>map</code>.
629 * Note that there is no documentation ****
630 * that this ordering is the same as the one
631 * of the value collection {@link Map#values() map#values()}. ****
632 */
633 private static <K, V> List<V> map2values(Map<K, V> map) {
634 List<V> res = new ArrayList<V>();
635 // **** using entrySet() would be more elegant,
636 // but seems not to guarantee an ordering of iteration.
637 for (K key : map.keySet()) {
638 res.add(map.get(key));
639 }
640 return res;
641 }
642
643 /**
644 * Creates a list map defined by the given keys and values
645 * <code>keys</code> and <code>values</code>.
646 * A key and a value correspond iff their index coincides.
647 * Thus <code>keys</code> and <code>values</code> must have the same size.
648 * Note that the entries of <code>keys</code> differ pairwise,
649 * whereas this is not necessary for <code>values</code>.
650 *
651 * @param keys
652 * the set of keys as a {@link ListSet}.
653 * @param values
654 * the collection of according values as a {@link List}
655 * with the same size as <code>keys</code>.
656 * @throws IllegalArgumentException
657 * if <code>keys</code> and <code>values</code> differ in size.
658 */
659 private ListMap(ListSet<K> keys, List<V> values) {
660 if (keys.size() != values.size()) {
661 throw new IllegalArgumentException
662 ("Collection of keys and values must have same size. ");
663 }
664
665 this.keys = keys;
666 this.values = values;
667 this.valuesColl = new Values();
668 this.keysSet = new Keys();
669 this.entrySet = new Entries();
670 }
671
672 /* -------------------------------------------------------------------- *
673 * Methods. *
674 * -------------------------------------------------------------------- */
675
676 public void clear() {
677 this.keys .clear();
678 this.values.clear();
679 }
680
681 public boolean containsKey(Object key) {
682 return this.keys.contains(key);
683 }
684
685 public boolean containsValue(Object val) {
686 return this.values.contains(val);
687 }
688
689 public SortedSet<Map.Entry<K, V>> entrySet() {
690 return this.entrySet;
691 }
692
693 public V get(Object key) {
694 int idx = this.keys.getList().indexOf(key);
695 if (idx == -1) {
696 return null;
697 }
698 assert idx >= 0 && idx < size();
699 return this.values.get(idx);
700 }
701
702 public boolean isEmpty() {
703 assert this.keys.isEmpty() == this.values.isEmpty();
704 return this.keys.isEmpty();
705 }
706
707 public SortedSet<K> keySet() {
708 return this.keysSet;
709 }
710
711 public V put(K key, V value) {
712 int idx = this.keys.getList().indexOf(key);
713 if (idx == -1) {
714 // Here, key is to be added
715 this.keys.getList().add(key);
716 this.values.add(value);
717 return null;
718 }
719 assert idx >= 0 && idx < size();
720
721 return this.values.set(idx, value);
722 }
723
724 public void putAll(Map<? extends K, ? extends V> other) {
725 Iterator<? extends K> iter = other.keySet().iterator();
726 K key;
727 while (iter.hasNext()) {
728 key = iter.next();
729 this.put(key, other.get(key));
730 }
731 }
732
733 public V remove(Object key) {
734 int idx = this.keys.getList().indexOf(key);
735 if (idx == -1) {
736 return null;
737 }
738 assert idx >= 0 && idx < size();
739 V res = this.values.get(idx);
740 this.keys.getList().remove(idx);
741 this.values.remove(idx);
742 return res;
743 }
744
745 private boolean removeIdx(int idx) {
746 if (idx == -1) {
747 return false;
748 }
749 assert idx >= 0 && idx < size();
750 this.keys.getList().remove(idx);
751 this.values.remove(idx);
752 return true;
753 }
754
755 public int size() {
756 return this.keys.size();
757 }
758
759 public Comparator<? super K> comparator() {
760 return this.keys.comparator();
761 }
762
763 public Collection<V> values() {
764 return this.valuesColl;
765 }
766
767 // also throws correct exception
768 public K firstKey() {
769 return keySet().first();
770 }
771
772 // also throws correct exception
773 public K lastKey() {
774 return keySet().last();
775 }
776
777 // better removed because easy to mix up with other methods
778 // offering just a view, not a copy of part of this map
779 // public Map<K,V> subMap(Set<K> someKeys) {
780 // V val;
781 // ListMap<K, V> res = new ListMap<K, V>();
782 // for (K key : someKeys) {
783 // val = get(key);
784 // res.put(key, val);
785 // }
786 // return res;
787 // }
788
789 public ListMap<K, V> headMap(K toKey) {
790 return subMap(0, this.keys.obj2idx(toKey));
791 }
792
793 public ListMap<K, V> tailMap(K fromKey) {
794 return subMap(this.keys.obj2idx(fromKey), size());
795 }
796
797
798 @SuppressWarnings("checkstyle:genericwhitespace")
799 ListMap<K, V> subMap(int fromIdx, int toIdx) {
800 ListSet<K> subKeys = this.keys .subSetIdx(fromIdx, toIdx);
801 List <V> subValues = this.values.subList (fromIdx, toIdx);
802
803 return new ListMap<K, V>(subKeys, subValues);
804 }
805
806 public ListMap<K, V> subMap(K fromKey, K toKey) {
807 return subMap(this.keys.obj2idx(fromKey), this.keys.obj2idx(toKey));
808 }
809
810 public boolean equals(Object obj) {
811 if (!(obj instanceof Map)) {
812 return false;
813 }
814
815 Map<?, ?> other = (Map<?, ?>) obj;
816 return this.entrySet().equals(other.entrySet());
817 }
818
819 public int hashCode() {
820 return this.entrySet().hashCode();
821 }
822
823 public String toString() {
824 StringBuffer result = new StringBuffer();
825 result.append("<ListMap>\n");
826 for (int i = 0; i < size(); i++) {
827 result.append("[" + this.keys.getList().get(i)
828 + " => " + this.values.get(i) + "]\n");
829 }
830 result.append("</ListMap>\n");
831
832 return result.toString();
833 }
834
835 public static void main(String[] args) {
836 List<Integer> list = new ArrayList<Integer>();
837 //list.add(0);
838 list.iterator().remove();
839 }
840 }