From 50a195ef78af5d15dd6e548d4d6928c281bbaac2 Mon Sep 17 00:00:00 2001 From: Adrien Hopkins Date: Fri, 3 May 2019 15:07:16 -0400 Subject: Added toString to UnitsDatabase and its helper classes. --- src/org/unitConverter/UnitsDatabase.java | 286 +++++++++++++++++++++++++------ 1 file changed, 229 insertions(+), 57 deletions(-) (limited to 'src/org/unitConverter/UnitsDatabase.java') diff --git a/src/org/unitConverter/UnitsDatabase.java b/src/org/unitConverter/UnitsDatabase.java index e5d2f67..37d53d4 100755 --- a/src/org/unitConverter/UnitsDatabase.java +++ b/src/org/unitConverter/UnitsDatabase.java @@ -75,7 +75,11 @@ public final class UnitsDatabase { *

* This map is infinite in size if there is at least one unit and at least one prefix. If it is infinite, some * operations that only work with finite collections, like converting name/entry sets to arrays, will throw an - * {@code UnsupportedOperationException}. + * {@code IllegalStateException}. + *

+ *

+ * Because of ambiguities between prefixes (i.e. kilokilo = mega), {@link #containsValue} and {@link #values()} + * currently ignore prefixes. *

* * @author Adrien Hopkins @@ -86,6 +90,12 @@ public final class UnitsDatabase { /** * The class used for entry sets. * + *

+ * If the map that created this set is infinite in size (has at least one unit and at least one prefix), this + * set is infinite as well. If this set is infinite in size, {@link #toArray} will fail with a + * {@code IllegalStateException} instead of creating an infinite-sized array. + *

+ * * @author Adrien Hopkins * @since 2019-04-13 * @since v0.2.0 @@ -117,6 +127,18 @@ public final class UnitsDatabase { this.value = value; } + /** + * @since 2019-05-03 + */ + @Override + public boolean equals(final Object o) { + if (!(o instanceof Map.Entry)) + return false; + final Map.Entry other = (Map.Entry) o; + return Objects.equals(this.getKey(), other.getKey()) + && Objects.equals(this.getValue(), other.getValue()); + } + @Override public String getKey() { return this.key; @@ -127,9 +149,29 @@ public final class UnitsDatabase { return this.value; } + /** + * @since 2019-05-03 + */ + @Override + public int hashCode() { + return (this.getKey() == null ? 0 : this.getKey().hashCode()) + ^ (this.getValue() == null ? 0 : this.getValue().hashCode()); + } + @Override public Unit setValue(final Unit value) { - throw new UnsupportedOperationException(); + throw new UnsupportedOperationException("Cannot set value in an immutable entry"); + } + + /** + * Returns a string representation of the entry. The format of the string is the string representation + * of the key, then the equals ({@code =}) character, then the string representation of the value. + * + * @since 2019-05-03 + */ + @Override + public String toString() { + return this.getKey() + "=" + this.getValue(); } } @@ -148,8 +190,8 @@ public final class UnitsDatabase { // values from the unit entry set private final Map map; - private final List unitNames; - private final List prefixNames; + private transient final List unitNames; + private transient final List prefixNames; /** * Creates the {@code UnitsDatabase.PrefixedUnitMap.PrefixedUnitNameSet.PrefixedUnitNameIterator}. @@ -157,10 +199,10 @@ public final class UnitsDatabase { * @since 2019-04-14 * @since v0.2.0 */ - public PrefixedUnitEntryIterator(final PrefixedUnitEntrySet set) { - this.map = set.map; - this.unitNames = new ArrayList<>(set.map.units.keySet()); - this.prefixNames = new ArrayList<>(set.map.prefixes.keySet()); + public PrefixedUnitEntryIterator(final PrefixedUnitMap map) { + this.map = map; + this.unitNames = new ArrayList<>(map.units.keySet()); + this.prefixNames = new ArrayList<>(map.prefixes.keySet()); } /** @@ -228,8 +270,23 @@ public final class UnitsDatabase { @Override public Entry next() { + // get next element + final Entry nextEntry = this.peek(); + + // iterate to next position + this.incrementPosition(); + + return nextEntry; + } + + /** + * @return the next element in the iterator, without iterating over it + * @since 2019-05-03 + */ + private Entry peek() { if (!this.hasNext()) throw new NoSuchElementException("No units left!"); + // if I have prefixes, ensure I'm not using a nonlinear unit // since all of the unprefixed stuff is done, just remove nonlinear units if (!this.prefixCoordinates.isEmpty()) { @@ -241,10 +298,20 @@ public final class UnitsDatabase { final String nextName = this.getCurrentUnitName(); - this.incrementPosition(); - return new PrefixedUnitEntry(nextName, this.map.get(nextName)); } + + /** + * Returns a string representation of the object. The exact details of the representation are + * unspecified and subject to change. + * + * @since 2019-05-03 + */ + @Override + public String toString() { + return String.format("Iterator iterating over name-unit entries; next value is \"%s\"", + this.peek()); + } } // the map that created this set @@ -264,17 +331,17 @@ public final class UnitsDatabase { @Override public boolean add(final Map.Entry e) { - throw new UnsupportedOperationException(); + throw new UnsupportedOperationException("Cannot add to an immutable set"); } @Override public boolean addAll(final Collection> c) { - throw new UnsupportedOperationException(); + throw new UnsupportedOperationException("Cannot add to an immutable set"); } @Override public void clear() { - throw new UnsupportedOperationException(); + throw new UnsupportedOperationException("Cannot clear an immutable set"); } @Override @@ -283,7 +350,7 @@ public final class UnitsDatabase { final Entry entry; try { - // This is OK because I'm in a try-catch block. + // This is OK because I'm in a try-catch block, catching the exact exception that would be thrown. @SuppressWarnings("unchecked") final Entry tempEntry = (Entry) o; entry = tempEntry; @@ -309,27 +376,27 @@ public final class UnitsDatabase { @Override public Iterator> iterator() { - return new PrefixedUnitEntryIterator(this); + return new PrefixedUnitEntryIterator(this.map); } @Override public boolean remove(final Object o) { - throw new UnsupportedOperationException(); + throw new UnsupportedOperationException("Cannot remove from an immutable set"); } @Override public boolean removeAll(final Collection c) { - throw new UnsupportedOperationException(); + throw new UnsupportedOperationException("Cannot remove from an immutable set"); } @Override public boolean removeIf(final Predicate> filter) { - throw new UnsupportedOperationException(); + throw new UnsupportedOperationException("Cannot remove from an immutable set"); } @Override public boolean retainAll(final Collection c) { - throw new UnsupportedOperationException(); + throw new UnsupportedOperationException("Cannot remove from an immutable set"); } @Override @@ -345,29 +412,51 @@ public final class UnitsDatabase { } } + /** + * @throws IllegalStateException + * if the set is infinite in size + */ @Override public Object[] toArray() { if (this.map.units.isEmpty() || this.map.prefixes.isEmpty()) return super.toArray(); else // infinite set - throw new UnsupportedOperationException("Cannot make an infinite set into an array."); + throw new IllegalStateException("Cannot make an infinite set into an array."); } + /** + * @throws IllegalStateException + * if the set is infinite in size + */ @Override public T[] toArray(final T[] a) { if (this.map.units.isEmpty() || this.map.prefixes.isEmpty()) return super.toArray(a); else // infinite set - throw new UnsupportedOperationException("Cannot make an infinite set into an array."); + throw new IllegalStateException("Cannot make an infinite set into an array."); } + @Override + public String toString() { + if (this.map.units.isEmpty() || this.map.prefixes.isEmpty()) + return super.toString(); + else + return String.format("Infinite set of name-unit entries created from units %s and prefixes %s", + this.map.units, this.map.prefixes); + } } /** * The class used for unit name sets. * + *

+ * If the map that created this set is infinite in size (has at least one unit and at least one prefix), this + * set is infinite as well. If this set is infinite in size, {@link #toArray} will fail with a + * {@code IllegalStateException} instead of creating an infinite-sized array. + *

+ * * @author Adrien Hopkins * @since 2019-04-13 * @since v0.2.0 @@ -388,8 +477,8 @@ public final class UnitsDatabase { // values from the unit name set private final Map map; - private final List unitNames; - private final List prefixNames; + private transient final List unitNames; + private transient final List prefixNames; /** * Creates the {@code UnitsDatabase.PrefixedUnitMap.PrefixedUnitNameSet.PrefixedUnitNameIterator}. @@ -397,10 +486,10 @@ public final class UnitsDatabase { * @since 2019-04-14 * @since v0.2.0 */ - public PrefixedUnitNameIterator(final PrefixedUnitNameSet set) { - this.map = set.map; - this.unitNames = new ArrayList<>(set.map.units.keySet()); - this.prefixNames = new ArrayList<>(set.map.prefixes.keySet()); + public PrefixedUnitNameIterator(final PrefixedUnitMap map) { + this.map = map; + this.unitNames = new ArrayList<>(map.units.keySet()); + this.prefixNames = new ArrayList<>(map.prefixes.keySet()); } /** @@ -468,6 +557,18 @@ public final class UnitsDatabase { @Override public String next() { + final String nextName = this.peek(); + + this.incrementPosition(); + + return nextName; + } + + /** + * @return the next element in the iterator, without iterating over it + * @since 2019-05-03 + */ + private String peek() { if (!this.hasNext()) throw new NoSuchElementException("No units left!"); // if I have prefixes, ensure I'm not using a nonlinear unit @@ -479,11 +580,18 @@ public final class UnitsDatabase { } } - final String nextName = this.getCurrentUnitName(); - - this.incrementPosition(); + return this.getCurrentUnitName(); + } - return nextName; + /** + * Returns a string representation of the object. The exact details of the representation are + * unspecified and subject to change. + * + * @since 2019-05-03 + */ + @Override + public String toString() { + return String.format("Iterator iterating over unit names; next value is \"%s\"", this.peek()); } } @@ -504,17 +612,17 @@ public final class UnitsDatabase { @Override public boolean add(final String e) { - throw new UnsupportedOperationException(); + throw new UnsupportedOperationException("Cannot add to an immutable set"); } @Override public boolean addAll(final Collection c) { - throw new UnsupportedOperationException(); + throw new UnsupportedOperationException("Cannot add to an immutable set"); } @Override public void clear() { - throw new UnsupportedOperationException(); + throw new UnsupportedOperationException("Cannot clear an immutable set"); } @Override @@ -537,27 +645,27 @@ public final class UnitsDatabase { @Override public Iterator iterator() { - return new PrefixedUnitNameIterator(this); + return new PrefixedUnitNameIterator(this.map); } @Override public boolean remove(final Object o) { - throw new UnsupportedOperationException(); + throw new UnsupportedOperationException("Cannot remove from an immutable set"); } @Override public boolean removeAll(final Collection c) { - throw new UnsupportedOperationException(); + throw new UnsupportedOperationException("Cannot remove from an immutable set"); } @Override public boolean removeIf(final Predicate filter) { - throw new UnsupportedOperationException(); + throw new UnsupportedOperationException("Cannot remove from an immutable set"); } @Override public boolean retainAll(final Collection c) { - throw new UnsupportedOperationException(); + throw new UnsupportedOperationException("Cannot remove from an immutable set"); } @Override @@ -573,23 +681,40 @@ public final class UnitsDatabase { } } + /** + * @throws IllegalStateException + * if the set is infinite in size + */ @Override public Object[] toArray() { if (this.map.units.isEmpty() || this.map.prefixes.isEmpty()) return super.toArray(); else // infinite set - throw new UnsupportedOperationException("Cannot make an infinite set into an array."); + throw new IllegalStateException("Cannot make an infinite set into an array."); } + /** + * @throws IllegalStateException + * if the set is infinite in size + */ @Override public T[] toArray(final T[] a) { if (this.map.units.isEmpty() || this.map.prefixes.isEmpty()) return super.toArray(a); else // infinite set - throw new UnsupportedOperationException("Cannot make an infinite set into an array."); + throw new IllegalStateException("Cannot make an infinite set into an array."); + } + + @Override + public String toString() { + if (this.map.units.isEmpty() || this.map.prefixes.isEmpty()) + return super.toString(); + else + return String.format("Infinite set of name-unit entries created from units %s and prefixes %s", + this.map.units, this.map.prefixes); } } @@ -610,9 +735,9 @@ public final class UnitsDatabase { private final Map prefixes; // caches - private Collection values = null; - private Set keySet = null; - private Set> entrySet = null; + private transient Collection values = null; + private transient Set keySet = null; + private transient Set> entrySet = null; /** * Creates the {@code PrefixedUnitMap}. @@ -632,24 +757,24 @@ public final class UnitsDatabase { @Override public void clear() { - throw new UnsupportedOperationException(); + throw new UnsupportedOperationException("Cannot clear an immutable map"); } @Override public Unit compute(final String key, final BiFunction remappingFunction) { - throw new UnsupportedOperationException(); + throw new UnsupportedOperationException("Cannot edit an immutable map"); } @Override public Unit computeIfAbsent(final String key, final Function mappingFunction) { - throw new UnsupportedOperationException(); + throw new UnsupportedOperationException("Cannot edit an immutable map"); } @Override public Unit computeIfPresent(final String key, final BiFunction remappingFunction) { - throw new UnsupportedOperationException(); + throw new UnsupportedOperationException("Cannot edit an immutable map"); } @Override @@ -685,6 +810,13 @@ public final class UnitsDatabase { return longestPrefix != null; } + /** + * {@inheritDoc} + * + *

+ * Because of ambiguities between prefixes (i.e. kilokilo = mega), this method only tests for prefixless units. + *

+ */ @Override public boolean containsValue(final Object value) { return this.units.containsValue(value); @@ -758,47 +890,47 @@ public final class UnitsDatabase { @Override public Unit merge(final String key, final Unit value, final BiFunction remappingFunction) { - throw new UnsupportedOperationException(); + throw new UnsupportedOperationException("Cannot merge into an immutable map"); } @Override public Unit put(final String key, final Unit value) { - throw new UnsupportedOperationException(); + throw new UnsupportedOperationException("Cannot add entries to an immutable map"); } @Override public void putAll(final Map m) { - throw new UnsupportedOperationException(); + throw new UnsupportedOperationException("Cannot add entries to an immutable map"); } @Override public Unit putIfAbsent(final String key, final Unit value) { - throw new UnsupportedOperationException(); + throw new UnsupportedOperationException("Cannot add entries to an immutable map"); } @Override public Unit remove(final Object key) { - throw new UnsupportedOperationException(); + throw new UnsupportedOperationException("Cannot remove entries from an immutable map"); } @Override public boolean remove(final Object key, final Object value) { - throw new UnsupportedOperationException(); + throw new UnsupportedOperationException("Cannot remove entries from an immutable map"); } @Override public Unit replace(final String key, final Unit value) { - throw new UnsupportedOperationException(); + throw new UnsupportedOperationException("Cannot replace entries in an immutable map"); } @Override public boolean replace(final String key, final Unit oldValue, final Unit newValue) { - throw new UnsupportedOperationException(); + throw new UnsupportedOperationException("Cannot replace entries in an immutable map"); } @Override public void replaceAll(final BiFunction function) { - throw new UnsupportedOperationException(); + throw new UnsupportedOperationException("Cannot replace entries in an immutable map"); } @Override @@ -814,6 +946,22 @@ public final class UnitsDatabase { } } + @Override + public String toString() { + if (this.units.isEmpty() || this.prefixes.isEmpty()) + return super.toString(); + else + return String.format("Infinite map of name-unit entries created from units %s and prefixes %s", + this.units, this.prefixes); + } + + /** + * {@inheritDoc} + * + *

+ * Because of ambiguities between prefixes (i.e. kilokilo = mega), this method ignores prefixes. + *

+ */ @Override public Collection values() { if (this.values == null) { @@ -1459,7 +1607,31 @@ public final class UnitsDatabase { return Collections.unmodifiableMap(this.prefixes); } + @Override + public String toString() { + return String.format("Unit Database with %d units and %d unit prefixes", this.prefixlessUnits.size(), + this.prefixes.size()); + } + /** + * Returns a map mapping unit names to units, including units with prefixes. + *

+ * The returned map is infinite in size if there is at least one unit and at least one prefix. If it is infinite, + * some operations that only work with finite collections, like converting name/entry sets to arrays, will throw an + * {@code IllegalStateException}. + *

+ *

+ * Specifically, the operations that will throw an IllegalStateException if the map is infinite in size are: + *

    + *
  • {@code unitMap.entrySet().toArray()} (either overloading)
  • + *
  • {@code unitMap.keySet().toArray()} (either overloading)
  • + *
+ *

+ *

+ * Because of ambiguities between prefixes (i.e. kilokilo = mega), the map's {@link PrefixedUnitMap#containsValue + * containsValue} and {@link PrefixedUnitMap#values() values()} methods currently ignore prefixes. + *

+ * * @return a map mapping unit names to units, including prefixed names * @since 2019-04-13 * @since v0.2.0 -- cgit v1.2.3