diff options
Diffstat (limited to 'src/org/unitConverter/unit/Unit.java')
-rw-r--r-- | src/org/unitConverter/unit/Unit.java | 342 |
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.")); } } |