77import java .util .Set ;
88import org .apache .commons .lang3 .tuple .Pair ;
99
10+ /**
11+ * A class that handles unit conversions using affine transformations.
12+ *
13+ * <p>The {@code UnitsConverter} allows converting values between different units using
14+ * pre-defined affine conversion formulas. Each conversion is represented by an
15+ * {@link AffineConverter} that defines the scaling and offset for the conversion.
16+ *
17+ * <p>For each unit, both direct conversions (e.g., Celsius to Fahrenheit) and inverse
18+ * conversions (e.g., Fahrenheit to Celsius) are generated automatically. It also computes
19+ * transitive conversions (e.g., Celsius to Kelvin via Fahrenheit if both conversions exist).
20+ *
21+ * <p>Key features include:
22+ * <ul>
23+ * <li>Automatic handling of inverse conversions (e.g., Fahrenheit to Celsius).</li>
24+ * <li>Compositional conversions, meaning if conversions between A -> B and B -> C exist,
25+ * it can automatically generate A -> C conversion.</li>
26+ * <li>Supports multiple unit systems as long as conversions are provided in pairs.</li>
27+ * </ul>
28+ *
29+ * <h2>Example Usage</h2>
30+ * <pre>
31+ * Map<Pair<String, String>, AffineConverter> basicConversions = Map.ofEntries(
32+ * entry(Pair.of("Celsius", "Fahrenheit"), new AffineConverter(9.0 / 5.0, 32.0)),
33+ * entry(Pair.of("Kelvin", "Celsius"), new AffineConverter(1.0, -273.15))
34+ * );
35+ *
36+ * UnitsConverter converter = new UnitsConverter(basicConversions);
37+ * double result = converter.convert("Celsius", "Fahrenheit", 100.0);
38+ * // Output: 212.0 (Celsius to Fahrenheit conversion of 100°C)
39+ * </pre>
40+ *
41+ * <h2>Exception Handling</h2>
42+ * <ul>
43+ * <li>If the input unit and output unit are the same, an {@link IllegalArgumentException} is thrown.</li>
44+ * <li>If a conversion between the requested units does not exist, a {@link NoSuchElementException} is thrown.</li>
45+ * </ul>
46+ */
1047public final class UnitsConverter {
1148 private final Map <Pair <String , String >, AffineConverter > conversions ;
1249 private final Set <String > units ;
@@ -68,11 +105,29 @@ private static Set<String> extractUnits(final Map<Pair<String, String>, AffineCo
68105 return res ;
69106 }
70107
108+ /**
109+ * Constructor for {@code UnitsConverter}.
110+ *
111+ * <p>Accepts a map of basic conversions and automatically generates inverse and
112+ * transitive conversions.
113+ *
114+ * @param basicConversions the initial set of unit conversions to add.
115+ */
71116 public UnitsConverter (final Map <Pair <String , String >, AffineConverter > basicConversions ) {
72117 conversions = computeAllConversions (basicConversions );
73118 units = extractUnits (conversions );
74119 }
75120
121+ /**
122+ * Converts a value from one unit to another.
123+ *
124+ * @param inputUnit the unit of the input value.
125+ * @param outputUnit the unit to convert the value into.
126+ * @param value the value to convert.
127+ * @return the converted value in the target unit.
128+ * @throws IllegalArgumentException if inputUnit equals outputUnit.
129+ * @throws NoSuchElementException if no conversion exists between the units.
130+ */
76131 public double convert (final String inputUnit , final String outputUnit , final double value ) {
77132 if (inputUnit .equals (outputUnit )) {
78133 throw new IllegalArgumentException ("inputUnit must be different from outputUnit." );
@@ -81,6 +136,11 @@ public double convert(final String inputUnit, final String outputUnit, final dou
81136 return conversions .computeIfAbsent (conversionKey , k -> { throw new NoSuchElementException ("No converter for: " + k ); }).convert (value );
82137 }
83138
139+ /**
140+ * Retrieves the set of all units supported by this converter.
141+ *
142+ * @return a set of available units.
143+ */
84144 public Set <String > availableUnits () {
85145 return units ;
86146 }
0 commit comments