summaryrefslogtreecommitdiff
path: root/src/org/unitConverter/unit/Unit.java
diff options
context:
space:
mode:
Diffstat (limited to 'src/org/unitConverter/unit/Unit.java')
-rw-r--r--src/org/unitConverter/unit/Unit.java342
1 files changed, 328 insertions, 14 deletions
diff --git a/src/org/unitConverter/unit/Unit.java b/src/org/unitConverter/unit/Unit.java
index 7971a41..d848ea1 100644
--- a/src/org/unitConverter/unit/Unit.java
+++ b/src/org/unitConverter/unit/Unit.java
@@ -16,9 +16,14 @@
*/
package org.unitConverter.unit;
+import java.util.Arrays;
+import java.util.Collections;
import java.util.HashMap;
+import java.util.HashSet;
import java.util.Map;
import java.util.Objects;
+import java.util.Optional;
+import java.util.Set;
import java.util.function.DoubleUnaryOperator;
import org.unitConverter.math.ObjectProduct;
@@ -31,6 +36,222 @@ import org.unitConverter.math.ObjectProduct;
*/
public abstract class Unit {
/**
+ * A class that can be used to specify names and a symbol for a unit.
+ *
+ * @author Adrien Hopkins
+ * @since 2019-10-21
+ */
+ public static final class NameSymbol {
+ public static final NameSymbol EMPTY = new NameSymbol(Optional.empty(), Optional.empty(), new HashSet<>());
+
+ /**
+ * Gets a {@code NameSymbol} with a primary name, a symbol and no other names.
+ *
+ * @param name
+ * name to use
+ * @param symbol
+ * symbol to use
+ * @return NameSymbol instance
+ * @since 2019-10-21
+ * @throws NullPointerException
+ * if name or symbol is null
+ */
+ public static final NameSymbol of(final String name, final String symbol) {
+ return new NameSymbol(Optional.of(name), Optional.of(symbol), new HashSet<>());
+ }
+
+ /**
+ * Gets a {@code NameSymbol} with a primary name, a symbol and additional names.
+ *
+ * @param name
+ * name to use
+ * @param symbol
+ * symbol to use
+ * @param otherNames
+ * other names to use
+ * @return NameSymbol instance
+ * @since 2019-10-21
+ * @throws NullPointerException
+ * if any argument is null
+ */
+ public static final NameSymbol of(final String name, final String symbol, final Set<String> otherNames) {
+ return new NameSymbol(Optional.of(name), Optional.of(symbol),
+ new HashSet<>(Objects.requireNonNull(otherNames, "otherNames must not be null.")));
+ }
+
+ /**
+ * h * Gets a {@code NameSymbol} with a primary name, a symbol and additional names.
+ *
+ * @param name
+ * name to use
+ * @param symbol
+ * symbol to use
+ * @param otherNames
+ * other names to use
+ * @return NameSymbol instance
+ * @since 2019-10-21
+ * @throws NullPointerException
+ * if any argument is null
+ */
+ public static final NameSymbol of(final String name, final String symbol, final String... otherNames) {
+ return new NameSymbol(Optional.of(name), Optional.of(symbol),
+ new HashSet<>(Arrays.asList(Objects.requireNonNull(otherNames, "otherNames must not be null."))));
+ }
+
+ /**
+ * Gets a {@code NameSymbol} with a primary name, a symbol and an additional name.
+ *
+ * @param name
+ * name to use
+ * @param symbol
+ * symbol to use
+ * @param otherNames
+ * other names to use
+ * @param name2
+ * alternate name
+ * @return NameSymbol instance
+ * @since 2019-10-21
+ * @throws NullPointerException
+ * if any argument is null
+ */
+ public static final NameSymbol of(final String name, final String symbol, final String name2) {
+ final Set<String> otherNames = new HashSet<>();
+ otherNames.add(Objects.requireNonNull(name2, "name2 must not be null."));
+ return new NameSymbol(Optional.of(name), Optional.of(symbol), otherNames);
+ }
+
+ /**
+ * Gets a {@code NameSymbol} with a primary name, a symbol and additional names.
+ *
+ * @param name
+ * name to use
+ * @param symbol
+ * symbol to use
+ * @param otherNames
+ * other names to use
+ * @param name2
+ * alternate name
+ * @param name3
+ * alternate name
+ * @return NameSymbol instance
+ * @since 2019-10-21
+ * @throws NullPointerException
+ * if any argument is null
+ */
+ public static final NameSymbol of(final String name, final String symbol, final String name2,
+ final String name3) {
+ final Set<String> otherNames = new HashSet<>();
+ otherNames.add(Objects.requireNonNull(name2, "name2 must not be null."));
+ otherNames.add(Objects.requireNonNull(name3, "name3 must not be null."));
+ return new NameSymbol(Optional.of(name), Optional.of(symbol), otherNames);
+ }
+
+ /**
+ * Gets a {@code NameSymbol} with a primary name, a symbol and additional names.
+ *
+ * @param name
+ * name to use
+ * @param symbol
+ * symbol to use
+ * @param otherNames
+ * other names to use
+ * @param name2
+ * alternate name
+ * @param name3
+ * alternate name
+ * @param name4
+ * alternate name
+ * @return NameSymbol instance
+ * @since 2019-10-21
+ * @throws NullPointerException
+ * if any argument is null
+ */
+ public static final NameSymbol of(final String name, final String symbol, final String name2,
+ final String name3, final String name4) {
+ final Set<String> otherNames = new HashSet<>();
+ otherNames.add(Objects.requireNonNull(name2, "name2 must not be null."));
+ otherNames.add(Objects.requireNonNull(name3, "name3 must not be null."));
+ otherNames.add(Objects.requireNonNull(name4, "name4 must not be null."));
+ return new NameSymbol(Optional.of(name), Optional.of(symbol), otherNames);
+ }
+
+ /**
+ * Gets a {@code NameSymbol} with a primary name, no symbol, and no other names.
+ *
+ * @param name
+ * name to use
+ * @return NameSymbol instance
+ * @since 2019-10-21
+ * @throws NullPointerException
+ * if name is null
+ */
+ public static final NameSymbol ofName(final String name) {
+ return new NameSymbol(Optional.of(name), Optional.empty(), new HashSet<>());
+ }
+
+ /**
+ * Gets a {@code NameSymbol} with a symbol and no names.
+ *
+ * @param symbol
+ * symbol to use
+ * @return NameSymbol instance
+ * @since 2019-10-21
+ * @throws NullPointerException
+ * if symbol is null
+ */
+ public static final NameSymbol ofSymbol(final String symbol) {
+ return new NameSymbol(Optional.empty(), Optional.of(symbol), new HashSet<>());
+ }
+
+ private final Optional<String> primaryName;
+ private final Optional<String> symbol;
+
+ private final Set<String> otherNames;
+
+ /**
+ * Creates the {@code NameSymbol}.
+ *
+ * @param primaryName
+ * primary name of unit
+ * @param symbol
+ * symbol used to represent unit
+ * @param otherNames
+ * other names and/or spellings
+ * @since 2019-10-21
+ */
+ private NameSymbol(final Optional<String> primaryName, final Optional<String> symbol,
+ final Set<String> otherNames) {
+ this.primaryName = primaryName;
+ this.symbol = symbol;
+ this.otherNames = Collections.unmodifiableSet(otherNames);
+ }
+
+ /**
+ * @return otherNames
+ * @since 2019-10-21
+ */
+ public final Set<String> getOtherNames() {
+ return this.otherNames;
+ }
+
+ /**
+ * @return primaryName
+ * @since 2019-10-21
+ */
+ public final Optional<String> getPrimaryName() {
+ return this.primaryName;
+ }
+
+ /**
+ * @return symbol
+ * @since 2019-10-21
+ */
+ public final Optional<String> getSymbol() {
+ return this.symbol;
+ }
+ }
+
+ /**
* Returns a unit from its base and the functions it uses to convert to and from its base.
*
* <p>
@@ -54,7 +275,36 @@ public abstract class Unit {
*/
public static final Unit fromConversionFunctions(final ObjectProduct<BaseUnit> base,
final DoubleUnaryOperator converterFrom, final DoubleUnaryOperator converterTo) {
- return FunctionalUnit.valueOf(base, converterFrom, converterTo);
+ return new FunctionalUnit(base, converterFrom, converterTo);
+ }
+
+ /**
+ * Returns a unit from its base and the functions it uses to convert to and from its base.
+ *
+ * <p>
+ * For example, to get a unit representing the degree Celsius, the following code can be used:
+ *
+ * {@code Unit.fromConversionFunctions(SI.KELVIN, tempK -> tempK - 273.15, tempC -> tempC + 273.15);}
+ * </p>
+ *
+ * @param base
+ * unit's base
+ * @param converterFrom
+ * function that accepts a value expressed in the unit's base and returns that value expressed in this
+ * unit.
+ * @param converterTo
+ * function that accepts a value expressed in the unit and returns that value expressed in the unit's
+ * base.
+ * @param ns
+ * names and symbol of unit
+ * @return a unit that uses the provided functions to convert.
+ * @since 2019-05-22
+ * @throws NullPointerException
+ * if any argument is null
+ */
+ public static final Unit fromConversionFunctions(final ObjectProduct<BaseUnit> base,
+ final DoubleUnaryOperator converterFrom, final DoubleUnaryOperator converterTo, final NameSymbol ns) {
+ return new FunctionalUnit(base, converterFrom, converterTo, ns);
}
/**
@@ -65,6 +315,21 @@ public abstract class Unit {
private final ObjectProduct<BaseUnit> unitBase;
/**
+ * The primary name used by this unit.
+ */
+ private final Optional<String> primaryName;
+
+ /**
+ * A short symbol used to represent this unit.
+ */
+ private final Optional<String> symbol;
+
+ /**
+ * A set of any additional names and/or spellings that the unit uses.
+ */
+ private final Set<String> otherNames;
+
+ /**
* Cache storing the result of getDimension()
*
* @since 2019-10-16
@@ -72,27 +337,37 @@ public abstract class Unit {
private transient ObjectProduct<BaseDimension> dimension = null;
/**
- * A constructor that constructs {@code BaseUnit} instances.
+ * Creates the {@code AbstractUnit}.
*
+ * @param unitBase
+ * base of unit
+ * @param ns
+ * names and symbol of unit
* @since 2019-10-16
+ * @throws NullPointerException
+ * if unitBase or ns is null
*/
- Unit() {
- if (this instanceof BaseUnit) {
- this.unitBase = ObjectProduct.oneOf((BaseUnit) this);
- } else
- throw new AssertionError();
+ protected Unit(final ObjectProduct<BaseUnit> unitBase, final NameSymbol ns) {
+ this.unitBase = Objects.requireNonNull(unitBase, "unitBase must not be null.");
+ this.primaryName = Objects.requireNonNull(ns, "ns must not be null.").getPrimaryName();
+ this.symbol = ns.getSymbol();
+ this.otherNames = ns.getOtherNames();
}
/**
- * Creates the {@code AbstractUnit}.
+ * A constructor that constructs {@code BaseUnit} instances.
*
- * @param unitBase
* @since 2019-10-16
- * @throws NullPointerException
- * if unitBase is null
*/
- protected Unit(final ObjectProduct<BaseUnit> unitBase) {
- this.unitBase = Objects.requireNonNull(unitBase, "unitBase must not be null.");
+ Unit(final String primaryName, final String symbol, final Set<String> otherNames) {
+ if (this instanceof BaseUnit) {
+ this.unitBase = ObjectProduct.oneOf((BaseUnit) this);
+ } else
+ throw new AssertionError();
+ this.primaryName = Optional.of(primaryName);
+ this.symbol = Optional.of(symbol);
+ this.otherNames = Collections.unmodifiableSet(
+ new HashSet<>(Objects.requireNonNull(otherNames, "additionalNames must not be null.")));
}
/**
@@ -208,8 +483,47 @@ public abstract class Unit {
return this.dimension;
}
+ /**
+ * @return additionalNames
+ * @since 2019-10-21
+ */
+ public final Set<String> getOtherNames() {
+ return this.otherNames;
+ }
+
+ /**
+ * @return primaryName
+ * @since 2019-10-21
+ */
+ public final Optional<String> getPrimaryName() {
+ return this.primaryName;
+ }
+
+ /**
+ * @return symbol
+ * @since 2019-10-21
+ */
+ public final Optional<String> getSymbol() {
+ return this.symbol;
+ }
+
@Override
public String toString() {
- return "Unit derived from base " + this.getBase().toString();
+ return this.getPrimaryName().orElse("Unnamed unit")
+ + (this.getSymbol().isPresent() ? String.format(" (%s)", this.getSymbol().get()) : "")
+ + ", derived from " + this.getBase().toString();
+ }
+
+ /**
+ * @param ns
+ * name(s) and symbol to use
+ * @return a copy of this unit with provided name(s) and symbol
+ * @since 2019-10-21
+ * @throws NullPointerException
+ * if ns is null
+ */
+ public Unit withName(final NameSymbol ns) {
+ return fromConversionFunctions(this.getBase(), this::convertFromBase, this::convertToBase,
+ Objects.requireNonNull(ns, "ns must not be null."));
}
}