001/* 002 * Units of Measurement Common Library 003 * Copyright (c) 2005-2018, Jean-Marie Dautelle, Werner Keil and others. 004 * 005 * All rights reserved. 006 * 007 * Redistribution and use in source and binary forms, with or without modification, 008 * are permitted provided that the following conditions are met: 009 * 010 * 1. Redistributions of source code must retain the above copyright notice, 011 * this list of conditions and the following disclaimer. 012 * 013 * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions 014 * and the following disclaimer in the documentation and/or other materials provided with the distribution. 015 * 016 * 3. Neither the name of JSR-363 nor the names of its contributors may be used to endorse or promote products 017 * derived from this software without specific prior written permission. 018 * 019 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 020 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 021 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 022 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 023 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 024 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 025 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 026 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 027 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, 028 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 029 */ 030package tech.uom.lib.common.function; 031 032import java.util.Comparator; 033import java.util.Objects; 034import java.util.function.BinaryOperator; 035import java.util.function.Function; 036import java.util.function.Predicate; 037import javax.measure.Quantity; 038import javax.measure.Unit; 039 040import tech.uom.lib.common.util.NaturalQuantityComparator; 041 042/** 043 * Utility methods for operating on {@link Unit units} and {@link Quantity quantities} with Java 044 * {@linkplain FunctionalInterface functional interfaces} like {@linkplain Function}. 045 * 046 * @author Otavio 047 * @author Werner 048 * @version 1.0.3 049 * @since 2.0 050 * 051 */ 052@SuppressWarnings("rawtypes") 053public final class QuantityFunctions { 054 055 private QuantityFunctions() { 056 throw new Error("no instances"); 057 } 058 059 /** 060 * Creates a comparator to sort by number, ignoring the unit. 061 * 062 * @return <p> 063 * <b>Given:</b> 064 * <p> 065 * <code> 066 * Quantity<Time> day = timeFactory.create(1, Units.DAY);<br> 067 * Quantity<Time> hours = timeFactory.create(18, Units.HOUR);<br> 068 * Quantity<Time> minutes = timeFactory.create(15, Units.HOUR);<br> 069 * Quantity<Time> seconds = timeFactory.create(100, Units.HOUR);<br> 070 * </code> 071 * <p> 072 * will return: <code>day, hours, minutes, seconds</code> 073 * </p> 074 * @throws NullPointerException 075 */ 076 public static <Q extends Quantity<Q>> Comparator<Quantity<Q>> sortNumber() { 077 return (q1, q2) -> Double.compare(q1.getValue().doubleValue(), q2.getValue().doubleValue()); 078 } 079 080 /** 081 * Creates a comparator to sort by number descending, ignoring the unit. 082 * 083 * @return <p> 084 * <b>Given:</b> 085 * <p> 086 * <code> 087 * Quantity<Time> day = timeFactory.create(1, Units.DAY);<br> 088 * Quantity<Time> hours = timeFactory.create(18, Units.HOUR);<br> 089 * Quantity<Time> minutes = timeFactory.create(15, Units.HOUR);<br> 090 * Quantity<Time> seconds = timeFactory.create(100, Units.HOUR);<br> 091 * </code> 092 * <p> 093 * will return: <code>seconds, hours, minutes, day</code> 094 * </p> 095 * @throws NullPointerException 096 */ 097 public static <Q extends Quantity<Q>> Comparator<Quantity<Q>> sortNumberDesc() { 098 Comparator<Quantity<Q>> sortNumber = sortNumber(); 099 return sortNumber.reversed(); 100 } 101 102 /** 103 * Creates a comparator to sort by name, ignoring the value. 104 * 105 * @return <p> 106 * <b>Given:</b> 107 * <p> 108 * <code> 109 * Quantity<Time> day = timeFactory.create(1, Units.DAY);<br> 110 * Quantity<Time> hours = timeFactory.create(18, Units.HOUR);<br> 111 * Quantity<Time> minutes = timeFactory.create(15, Units.HOUR);<br> 112 * Quantity<Time> seconds = timeFactory.create(100, Units.HOUR);<br> 113 * </code> 114 * <p> 115 * will return: <code>day, hours, minutes, seconds</code> 116 * </p> 117 * @throws NullPointerException 118 */ 119 public static <Q extends Quantity<Q>> Comparator<Quantity<Q>> sortSymbol() { 120 return (q1, q2) -> q1.getUnit().getSymbol().compareTo(q2.getUnit().getSymbol()); 121 } 122 123 /** 124 * Creates a comparator to sort by name descending, ignoring the value. 125 * 126 * @return <p> 127 * <b>Given:</b> 128 * </p> 129 * <code> 130 * Quantity<Time> day = timeFactory.create(1, Units.DAY);<br> 131 * Quantity<Time> hours = timeFactory.create(18, Units.HOUR);<br> 132 * Quantity<Time> minutes = timeFactory.create(15, Units.HOUR);<br> 133 * Quantity<Time> seconds = timeFactory.create(100, Units.HOUR);<br> 134 * </code> 135 * <p> 136 * will return: <code>seconds, minutes, hour, day</code> 137 * </p> 138 * @throws NullPointerException 139 */ 140 public static <Q extends Quantity<Q>> Comparator<Quantity<Q>> sortSymbolDesc() { 141 Comparator<Quantity<Q>> sortSymbol = sortSymbol(); 142 return sortSymbol.reversed(); 143 } 144 145 /** 146 * Creates a comparator to sort by natural order, looking to both the unit and the value. 147 * 148 * @return <p> 149 * <b>Given:</b> 150 * </p> 151 * <code> 152 * Quantity<Time> day = timeFactory.create(1, Units.DAY);<br> 153 * Quantity<Time> hours = timeFactory.create(18, Units.HOUR);<br> 154 * Quantity<Time> minutes = timeFactory.create(15, Units.HOUR);<br> 155 * Quantity<Time> seconds = timeFactory.create(100, Units.HOUR);<br> 156 * </code> 157 * <p> 158 * will return: <code>seconds, minutes, hours, day</code> 159 * </p> 160 * @throws NullPointerException 161 */ 162 @SuppressWarnings("unchecked") 163 public static <Q extends Quantity<Q>> Comparator<Quantity<Q>> sortNatural() { 164 return new NaturalQuantityComparator(); 165 } 166 167 /** 168 * Creates a comparator to sort by natural order descending, looking to both the unit and the value. 169 * 170 * @return <p> 171 * <b>Given:</b> 172 * </p> 173 * <code> 174 * Quantity<Time> day = timeFactory.create(1, Units.DAY);<br> 175 * Quantity<Time> hours = timeFactory.create(18, Units.HOUR);<br> 176 * Quantity<Time> minutes = timeFactory.create(15, Units.HOUR);<br> 177 * Quantity<Time> seconds = timeFactory.create(100, Units.HOUR);<br> 178 * </code> 179 * <p> 180 * will return: <code>day, hour, minute, second</code> 181 * </p> 182 * @throws NullPointerException 183 */ 184 public static <Q extends Quantity<Q>> Comparator<Quantity<Q>> sortNaturalDesc() { 185 Comparator<Quantity<Q>> sortNatural = sortNatural(); 186 return sortNatural.reversed(); 187 } 188 189 /** 190 * Creates a BinaryOperator to calculate the minimum Quantity 191 * 192 * @return the min BinaryOperator, not null. 193 */ 194 public static <Q extends Quantity<Q>> BinaryOperator<Quantity<Q>> min() { 195 196 return (q1, q2) -> { 197 double d1 = q1.getValue().doubleValue(); 198 double d2 = q2.to(q1.getUnit()).getValue().doubleValue(); 199 double min = Double.min(d1, d2); 200 if (min == d1) { 201 return q1; 202 } 203 return q2; 204 }; 205 } 206 207 /** 208 * Creates a BinaryOperator to calculate the maximum Quantity 209 * 210 * @return the max BinaryOperator, not null. 211 */ 212 public static <Q extends Quantity<Q>> BinaryOperator<Quantity<Q>> max() { 213 214 return (q1, q2) -> { 215 double d1 = q1.getValue().doubleValue(); 216 double d2 = q2.to(q1.getUnit()).getValue().doubleValue(); 217 double min = Double.max(d1, d2); 218 if (min == d1) { 219 return q1; 220 } 221 return q2; 222 }; 223 } 224 225 /** 226 * Creates a BinaryOperator to sum. 227 * 228 * @return the sum BinaryOperator 229 */ 230 public static <Q extends Quantity<Q>> BinaryOperator<Quantity<Q>> sum() { 231 return Quantity::add; 232 } 233 234 /** 235 * Creates a BinaryOperator to sum converting to unit 236 * 237 * @param unit 238 * unit to be converting 239 * @return the sum BinaryOperator converting to unit 240 */ 241 public static <Q extends Quantity<Q>> BinaryOperator<Quantity<Q>> sum(Unit<Q> unit) { 242 return (q1, q2) -> q1.to(unit).add(q2.to(unit)); 243 } 244 245 /** 246 * Predicate to filter to one or more units 247 * 248 * @param units 249 * - units to be filtered (optional) 250 * @return A predicate to filter one or more units 251 */ 252 @SafeVarargs 253 public static <Q extends Quantity<Q>> Predicate<Quantity<Q>> fiterByUnit(Unit<Q>... units) { 254 255 if (Objects.isNull(units) || units.length == 0) { 256 return q -> true; 257 } 258 Predicate<Quantity<Q>> predicate = null; 259 for (Unit<Q> u : units) { 260 if (Objects.isNull(predicate)) { 261 predicate = q -> q.getUnit().equals(u); 262 } else { 263 predicate = predicate.or(q -> q.getUnit().equals(u)); 264 } 265 } 266 return predicate; 267 } 268 269 /** 270 * Predicate to filter excluding these units 271 * 272 * @param units 273 * - units to be filtered (optional) 274 * @return A predicate to filter to not be these units 275 */ 276 @SafeVarargs 277 public static <Q extends Quantity<Q>> Predicate<Quantity<Q>> fiterByExcludingUnit(Unit<Q>... units) { 278 if (Objects.isNull(units) || units.length == 0) { 279 return q -> true; 280 } 281 return fiterByUnit(units).negate(); 282 } 283 284 /** 285 * creates a Filter to greater than number, ignoring units 286 * 287 * @param value 288 * - the value to be used in Predicate 289 * @return the Predicate greater than this number, ignoring units 290 */ 291 public static <Q extends Quantity<Q>> Predicate<Quantity<Q>> isGreaterThan(Number value) { 292 return q -> q.getValue().doubleValue() > value.doubleValue(); 293 } 294 295 /** 296 * creates a filter to greater than the quantity measure 297 * 298 * @param quantity 299 * - the measure to be used in filter 300 * @return the Predicate greater than this measure 301 */ 302 public static <Q extends Quantity<Q>> Predicate<Quantity<Q>> isGreaterThan(Quantity<Q> quantity) { 303 return q -> q.to(quantity.getUnit()).getValue().doubleValue() > quantity.getValue().doubleValue(); 304 } 305 306 /** 307 * creates a Filter to greater or equals than number, ignoring units 308 * 309 * @param value 310 * - the value to be used in Predicate 311 * @return the Predicate greater or equals than this number, ignoring units 312 */ 313 public static <Q extends Quantity<Q>> Predicate<Quantity<Q>> isGreaterThanOrEqualTo(Number value) { 314 return q -> q.getValue().doubleValue() >= value.doubleValue(); 315 } 316 317 /** 318 * creates a filter to greater or equals than the quantity measure 319 * 320 * @param quantity 321 * - the measure to be used in filter 322 * @return the Predicate greater or equals than this measure 323 */ 324 public static <Q extends Quantity<Q>> Predicate<Quantity<Q>> isGreaterThanOrEqualTo(Quantity<Q> quantity) { 325 return q -> q.to(quantity.getUnit()).getValue().doubleValue() >= quantity.getValue().doubleValue(); 326 } 327 328 /** 329 * creates a Filter to lesser than number, ignoring units 330 * 331 * @param value 332 * - the value to be used in Predicate 333 * @return the Predicate greater than this number, ignoring units 334 */ 335 public static <Q extends Quantity<Q>> Predicate<Quantity<Q>> isLessThan(Number value) { 336 return q -> q.getValue().doubleValue() < value.doubleValue(); 337 } 338 339 /** 340 * creates a filter to lesser than the quantity measure 341 * 342 * @param quantity 343 * - the measure to be used in filter 344 * @return the Predicate lesser than this measure 345 */ 346 public static <Q extends Quantity<Q>> Predicate<Quantity<Q>> isLessThan(Quantity<Q> quantity) { 347 return q -> q.to(quantity.getUnit()).getValue().doubleValue() < quantity.getValue().doubleValue(); 348 } 349 350 /** 351 * creates a Filter to lesser or equals than number, ignoring units 352 * 353 * @param value 354 * - the value to be used in Predicate 355 * @return the Predicate lesser or equals than this number, ignoring units 356 */ 357 public static <Q extends Quantity<Q>> Predicate<Quantity<Q>> isLessThanOrEqualTo(Number value) { 358 return q -> q.getValue().doubleValue() <= value.doubleValue(); 359 } 360 361 /** 362 * creates a filter to lesser or equals than the quantity measure 363 * 364 * @param quantity 365 * - the measure to be used in filter 366 * @return the Predicate lesser or equals than this measure 367 */ 368 public static <Q extends Quantity<Q>> Predicate<Quantity<Q>> isLessThanOrEqualTo(Quantity<Q> quantity) { 369 return q -> q.to(quantity.getUnit()).getValue().doubleValue() <= quantity.getValue().doubleValue(); 370 } 371 372 /** 373 * creates a Filter to between, lesser or equals and greater or equals, than number, ignoring units 374 * 375 * @param min 376 * - the min value to be used in Predicate 377 * @param max 378 * - the max value to be used in Predicate 379 * @return the Predicate lesser or equals than this number, ignoring units 380 */ 381 public static <Q extends Quantity<Q>> Predicate<Quantity<Q>> isBetween(Number min, Number max) { 382 Predicate<Quantity<Q>> minFilter = isGreaterThanOrEqualTo(min); 383 Predicate<Quantity<Q>> maxFilter = isLessThanOrEqualTo(max); 384 return minFilter.and(maxFilter); 385 } 386 387 /** 388 * creates a filter to between, lesser or equals and greater or equals, than the quantity measure 389 * 390 * @param min 391 * - the min value to be used in Predicate 392 * @param max 393 * - the max value to be used in Predicate 394 * @return the Predicate lesser or equals than this measure 395 */ 396 public static <Q extends Quantity<Q>> Predicate<Quantity<Q>> isBetween(Quantity<Q> min, Quantity<Q> max) { 397 return isGreaterThanOrEqualTo(min).and(isLessThanOrEqualTo(max)); 398 } 399 400 /** 401 * creates a function to group quantities by their {@link Unit unit}. 402 * 403 * @return the Function of {@link Quantity} grouped by {@link Unit} 404 */ 405 public static <Q extends Quantity<Q>> Function<Quantity<Q>, Unit<Q>> groupByUnit() { 406 return Quantity::getUnit; 407 } 408}