diff options
Diffstat (limited to 'src/org/unitConverter/UnitsDatabase.java')
-rwxr-xr-x | src/org/unitConverter/UnitsDatabase.java | 286 |
1 files changed, 229 insertions, 57 deletions
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 { * <p> * 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}. + * </p> + * <p> + * Because of ambiguities between prefixes (i.e. kilokilo = mega), {@link #containsValue} and {@link #values()} + * currently ignore prefixes. * </p> * * @author Adrien Hopkins @@ -86,6 +90,12 @@ public final class UnitsDatabase { /** * The class used for entry sets. * + * <p> + * 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. + * </p> + * * @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<String, Unit> map; - private final List<String> unitNames; - private final List<String> prefixNames; + private transient final List<String> unitNames; + private transient final List<String> 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<String, Unit> next() { + // get next element + final Entry<String, Unit> 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<String, Unit> 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<String, Unit> e) { - throw new UnsupportedOperationException(); + throw new UnsupportedOperationException("Cannot add to an immutable set"); } @Override public boolean addAll(final Collection<? extends Map.Entry<String, Unit>> 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<String, Unit> 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<String, Unit> tempEntry = (Entry<String, Unit>) o; entry = tempEntry; @@ -309,27 +376,27 @@ public final class UnitsDatabase { @Override public Iterator<Entry<String, Unit>> 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<? super Entry<String, Unit>> 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> 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. * + * <p> + * 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. + * </p> + * * @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<String, Unit> map; - private final List<String> unitNames; - private final List<String> prefixNames; + private transient final List<String> unitNames; + private transient final List<String> 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<? extends String> 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<String> 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<? super String> 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> 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<String, UnitPrefix> prefixes; // caches - private Collection<Unit> values = null; - private Set<String> keySet = null; - private Set<Entry<String, Unit>> entrySet = null; + private transient Collection<Unit> values = null; + private transient Set<String> keySet = null; + private transient Set<Entry<String, Unit>> 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<? super String, ? super Unit, ? extends Unit> remappingFunction) { - throw new UnsupportedOperationException(); + throw new UnsupportedOperationException("Cannot edit an immutable map"); } @Override public Unit computeIfAbsent(final String key, final Function<? super String, ? extends Unit> mappingFunction) { - throw new UnsupportedOperationException(); + throw new UnsupportedOperationException("Cannot edit an immutable map"); } @Override public Unit computeIfPresent(final String key, final BiFunction<? super String, ? super Unit, ? extends Unit> 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} + * + * <p> + * Because of ambiguities between prefixes (i.e. kilokilo = mega), this method only tests for prefixless units. + * </p> + */ @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<? super Unit, ? super Unit, ? extends Unit> 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<? extends String, ? extends Unit> 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<? super String, ? super Unit, ? extends Unit> function) { - throw new UnsupportedOperationException(); + throw new UnsupportedOperationException("Cannot replace entries in an immutable map"); } @Override @@ -815,6 +947,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} + * + * <p> + * Because of ambiguities between prefixes (i.e. kilokilo = mega), this method ignores prefixes. + * </p> + */ + @Override public Collection<Unit> values() { if (this.values == null) { this.values = Collections.unmodifiableCollection(this.units.values()); @@ -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. + * <p> + * 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}. + * </p> + * <p> + * Specifically, the operations that will throw an IllegalStateException if the map is infinite in size are: + * <ul> + * <li>{@code unitMap.entrySet().toArray()} (either overloading)</li> + * <li>{@code unitMap.keySet().toArray()} (either overloading)</li> + * </ul> + * </p> + * <p> + * 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. + * </p> + * * @return a map mapping unit names to units, including prefixed names * @since 2019-04-13 * @since v0.2.0 |