7
7
import java .util .Set ;
8
8
import org .apache .commons .lang3 .tuple .Pair ;
9
9
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
+ */
10
47
public final class UnitsConverter {
11
48
private final Map <Pair <String , String >, AffineConverter > conversions ;
12
49
private final Set <String > units ;
@@ -68,11 +105,29 @@ private static Set<String> extractUnits(final Map<Pair<String, String>, AffineCo
68
105
return res ;
69
106
}
70
107
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
+ */
71
116
public UnitsConverter (final Map <Pair <String , String >, AffineConverter > basicConversions ) {
72
117
conversions = computeAllConversions (basicConversions );
73
118
units = extractUnits (conversions );
74
119
}
75
120
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
+ */
76
131
public double convert (final String inputUnit , final String outputUnit , final double value ) {
77
132
if (inputUnit .equals (outputUnit )) {
78
133
throw new IllegalArgumentException ("inputUnit must be different from outputUnit." );
@@ -81,6 +136,11 @@ public double convert(final String inputUnit, final String outputUnit, final dou
81
136
return conversions .computeIfAbsent (conversionKey , k -> { throw new NoSuchElementException ("No converter for: " + k ); }).convert (value );
82
137
}
83
138
139
+ /**
140
+ * Retrieves the set of all units supported by this converter.
141
+ *
142
+ * @return a set of available units.
143
+ */
84
144
public Set <String > availableUnits () {
85
145
return units ;
86
146
}
0 commit comments