001/* 002 * Units of Measurement Implementation for Java SE 003 * Copyright (c) 2005-2017, Jean-Marie Dautelle, Werner Keil, V2COM. 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 tec.uom.se.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 java.util.function.Supplier; 038import java.util.stream.Collector; 039 040import javax.measure.Quantity; 041import javax.measure.Unit; 042 043/** 044 * @author Otavio 045 * @author Werner 046 * @version 1.0 047 * @since 1.0 048 * 049 */ 050@SuppressWarnings("rawtypes") 051public final class QuantityFunctions { 052 053 private QuantityFunctions() { 054 } 055 056 /** 057 * Creates a comparator to sort by number, ignoring the unit. 058 * 059 * @return <p> 060 * <b>Given:</b> 061 * <p> 062 * <code> 063 * Quantity<Time> day = timeFactory.create(1, Units.DAY);<br/> 064 * Quantity<Time> hours = timeFactory.create(18, Units.HOUR);<br/> 065 * Quantity<Time> minutes = timeFactory.create(15, Units.HOUR);<br/> 066 * Quantity<Time> seconds = timeFactory.create(100, Units.HOUR);<br/> 067 * </code> 068 * <p> 069 * will return: <code>day, hours, minutes, seconds</code> 070 * </p> 071 * @throws NullPointerException 072 */ 073 public static <Q extends Quantity<Q>> Comparator<Quantity<Q>> sortNumber() { 074 return (q1, q2) -> Double.compare(q1.getValue().doubleValue(), q2.getValue().doubleValue()); 075 } 076 077 /** 078 * Creates a comparator to sort by number descending, ignoring the unit. 079 * 080 * @return <p> 081 * <b>Given:</b> 082 * <p> 083 * <code> 084 * Quantity<Time> day = timeFactory.create(1, Units.DAY);<br/> 085 * Quantity<Time> hours = timeFactory.create(18, Units.HOUR);<br/> 086 * Quantity<Time> minutes = timeFactory.create(15, Units.HOUR);<br/> 087 * Quantity<Time> seconds = timeFactory.create(100, Units.HOUR);<br/> 088 * </code> 089 * <p> 090 * will return: <code>seconds, hours, minutes, day</code> 091 * </p> 092 * @throws NullPointerException 093 */ 094 public static <Q extends Quantity<Q>> Comparator<Quantity<Q>> sortNumberDesc() { 095 Comparator<Quantity<Q>> sortNumber = sortNumber(); 096 return sortNumber.reversed(); 097 } 098 099 /** 100 * Creates a comparator to sort by name, ignoring the value. 101 * 102 * @return <p> 103 * <b>Given:</b> 104 * <p> 105 * <code> 106 * Quantity<Time> day = timeFactory.create(1, Units.DAY);<br/> 107 * Quantity<Time> hours = timeFactory.create(18, Units.HOUR);<br/> 108 * Quantity<Time> minutes = timeFactory.create(15, Units.HOUR);<br/> 109 * Quantity<Time> seconds = timeFactory.create(100, Units.HOUR);<br/> 110 * </code> 111 * <p> 112 * will return: <code>day, hours, minutes, seconds</code> 113 * </p> 114 * @throws NullPointerException 115 */ 116 public static <Q extends Quantity<Q>> Comparator<Quantity<Q>> sortSymbol() { 117 return (q1, q2) -> q1.getUnit().getSymbol().compareTo(q2.getUnit().getSymbol()); 118 } 119 120 /** 121 * Creates a comparator to sort by name descending, ignoring the value. 122 * 123 * @return <p> 124 * <b>Given:</b> 125 * </p> 126 * <code> 127 * Quantity<Time> day = timeFactory.create(1, Units.DAY);<br/> 128 * Quantity<Time> hours = timeFactory.create(18, Units.HOUR);<br/> 129 * Quantity<Time> minutes = timeFactory.create(15, Units.HOUR);<br/> 130 * Quantity<Time> seconds = timeFactory.create(100, Units.HOUR);<br/> 131 * </code> 132 * <p> 133 * will return: <code>seconds, minutes, hour, day</code> 134 * </p> 135 * @throws NullPointerException 136 */ 137 public static <Q extends Quantity<Q>> Comparator<Quantity<Q>> sortSymbolDesc() { 138 Comparator<Quantity<Q>> sortSymbol = sortSymbol(); 139 return sortSymbol.reversed(); 140 } 141 142 /** 143 * Creates a comparator to sort by natural order, looking to both the unit and the value. 144 * 145 * @return <p> 146 * <b>Given:</b> 147 * </p> 148 * <code> 149 * Quantity<Time> day = timeFactory.create(1, Units.DAY);<br/> 150 * Quantity<Time> hours = timeFactory.create(18, Units.HOUR);<br/> 151 * Quantity<Time> minutes = timeFactory.create(15, Units.HOUR);<br/> 152 * Quantity<Time> seconds = timeFactory.create(100, Units.HOUR);<br/> 153 * </code> 154 * <p> 155 * will return: <code>seconds, minutes, hours, day</code> 156 * </p> 157 * @throws NullPointerException 158 */ 159 @SuppressWarnings("unchecked") 160 public static <Q extends Quantity<Q>> Comparator<Quantity<Q>> sortNatural() { 161 return new NaturalOrder(); 162 } 163 164 /** 165 * Creates a comparator to sort by natural order descending, looking to both the unit and the value. 166 * 167 * @return <p> 168 * <b>Given:</b> 169 * </p> 170 * <code> 171 * Quantity<Time> day = timeFactory.create(1, Units.DAY);<br/> 172 * Quantity<Time> hours = timeFactory.create(18, Units.HOUR);<br/> 173 * Quantity<Time> minutes = timeFactory.create(15, Units.HOUR);<br/> 174 * Quantity<Time> seconds = timeFactory.create(100, Units.HOUR);<br/> 175 * </code> 176 * <p> 177 * will return: <code>day, hour, minute, second</code> 178 * </p> 179 * @throws NullPointerException 180 */ 181 public static <Q extends Quantity<Q>> Comparator<Quantity<Q>> sortNaturalDesc() { 182 Comparator<Quantity<Q>> sortNatural = sortNatural(); 183 return sortNatural.reversed(); 184 } 185 186 /** 187 * Creates a BinaryOperator to calculate the minimum Quantity 188 * 189 * @return the min BinaryOperator, not null. 190 */ 191 public static <Q extends Quantity<Q>> BinaryOperator<Quantity<Q>> min() { 192 193 return (q1, q2) -> { 194 double d1 = q1.getValue().doubleValue(); 195 double d2 = q2.to(q1.getUnit()).getValue().doubleValue(); 196 double min = Double.min(d1, d2); 197 if (min == d1) { 198 return q1; 199 } 200 return q2; 201 }; 202 } 203 204 /** 205 * Creates a BinaryOperator to calculate the maximum Quantity 206 * 207 * @return the max BinaryOperator, not null. 208 */ 209 public static <Q extends Quantity<Q>> BinaryOperator<Quantity<Q>> max() { 210 211 return (q1, q2) -> { 212 double d1 = q1.getValue().doubleValue(); 213 double d2 = q2.to(q1.getUnit()).getValue().doubleValue(); 214 double min = Double.max(d1, d2); 215 if (min == d1) { 216 return q1; 217 } 218 return q2; 219 }; 220 } 221 222 /** 223 * Creates a BinaryOperator to sum. 224 * 225 * @return the sum BinaryOperator 226 */ 227 public static <Q extends Quantity<Q>> BinaryOperator<Quantity<Q>> sum() { 228 return Quantity::add; 229 } 230 231 /** 232 * Creates a BinaryOperator to sum converting to unit 233 * 234 * @param unit 235 * unit to be converting 236 * @return the sum BinaryOperator converting to unit 237 */ 238 public static <Q extends Quantity<Q>> BinaryOperator<Quantity<Q>> sum(Unit<Q> unit) { 239 return (q1, q2) -> q1.to(unit).add(q2.to(unit)); 240 } 241 242 /** 243 * Predicate to filter to one or more units 244 * 245 * @param units 246 * - units to be filtered (optional) 247 * @return A predicate to filter one or more units 248 */ 249 @SafeVarargs 250 public static <Q extends Quantity<Q>> Predicate<Quantity<Q>> fiterByUnit(Unit<Q>... units) { 251 252 if (Objects.isNull(units) || units.length == 0) { 253 return q -> true; 254 } 255 Predicate<Quantity<Q>> predicate = null; 256 for (Unit<Q> u : units) { 257 if (Objects.isNull(predicate)) { 258 predicate = q -> q.getUnit().equals(u); 259 } else { 260 predicate = predicate.or(q -> q.getUnit().equals(u)); 261 } 262 } 263 return predicate; 264 } 265 266 /** 267 * Predicate to filter excluding these units 268 * 269 * @param units 270 * - units to be filtered (optional) 271 * @return A predicate to filter to not be these units 272 */ 273 @SafeVarargs 274 public static <Q extends Quantity<Q>> Predicate<Quantity<Q>> fiterByExcludingUnit(Unit<Q>... units) { 275 if (Objects.isNull(units) || units.length == 0) { 276 return q -> true; 277 } 278 return fiterByUnit(units).negate(); 279 } 280 281 /** 282 * creates a Filter to greater than number, ignoring units 283 * 284 * @param value 285 * - the value to be used in Predicate 286 * @return the Predicate greater than this number, ignoring units 287 */ 288 public static <Q extends Quantity<Q>> Predicate<Quantity<Q>> isGreaterThan(Number value) { 289 return q -> q.getValue().doubleValue() > value.doubleValue(); 290 } 291 292 /** 293 * creates a filter to greater than the quantity measure 294 * 295 * @param quantity 296 * - the measure to be used in filter 297 * @return the Predicate greater than this measure 298 */ 299 public static <Q extends Quantity<Q>> Predicate<Quantity<Q>> isGreaterThan(Quantity<Q> quantity) { 300 return q -> q.to(quantity.getUnit()).getValue().doubleValue() > quantity.getValue().doubleValue(); 301 } 302 303 /** 304 * creates a Filter to greater or equals than number, ignoring units 305 * 306 * @param value 307 * - the value to be used in Predicate 308 * @return the Predicate greater or equals than this number, ignoring units 309 */ 310 public static <Q extends Quantity<Q>> Predicate<Quantity<Q>> isGreaterThanOrEqualTo(Number value) { 311 return q -> q.getValue().doubleValue() >= value.doubleValue(); 312 } 313 314 /** 315 * creates a filter to greater or equals than the quantity measure 316 * 317 * @param quantity 318 * - the measure to be used in filter 319 * @return the Predicate greater or equals than this measure 320 */ 321 public static <Q extends Quantity<Q>> Predicate<Quantity<Q>> isGreaterThanOrEqualTo(Quantity<Q> quantity) { 322 return q -> q.to(quantity.getUnit()).getValue().doubleValue() >= quantity.getValue().doubleValue(); 323 } 324 325 /** 326 * creates a Filter to lesser than number, ignoring units 327 * 328 * @param value 329 * - the value to be used in Predicate 330 * @return the Predicate greater than this number, ignoring units 331 */ 332 public static <Q extends Quantity<Q>> Predicate<Quantity<Q>> isLesserThan(Number value) { 333 return q -> q.getValue().doubleValue() < value.doubleValue(); 334 } 335 336 /** 337 * creates a filter to lesser than the quantity measure 338 * 339 * @param quantity 340 * - the measure to be used in filter 341 * @return the Predicate lesser than this measure 342 */ 343 public static <Q extends Quantity<Q>> Predicate<Quantity<Q>> isLesserThan(Quantity<Q> quantity) { 344 return q -> q.to(quantity.getUnit()).getValue().doubleValue() < quantity.getValue().doubleValue(); 345 } 346 347 /** 348 * creates a Filter to lesser or equals than number, ignoring units 349 * 350 * @param value 351 * - the value to be used in Predicate 352 * @return the Predicate lesser or equals than this number, ignoring units 353 */ 354 public static <Q extends Quantity<Q>> Predicate<Quantity<Q>> isLesserThanOrEqualTo(Number value) { 355 return q -> q.getValue().doubleValue() <= value.doubleValue(); 356 } 357 358 /** 359 * creates a filter to lesser or equals than the quantity measure 360 * 361 * @param quantity 362 * - the measure to be used in filter 363 * @return the Predicate lesser or equals than this measure 364 */ 365 public static <Q extends Quantity<Q>> Predicate<Quantity<Q>> isLesserThanOrEqualTo(Quantity<Q> quantity) { 366 return q -> q.to(quantity.getUnit()).getValue().doubleValue() <= quantity.getValue().doubleValue(); 367 } 368 369 /** 370 * creates a Filter to between, lesser or equals and greater or equals, than number, ignoring units 371 * 372 * @param min 373 * - the min value to be used in Predicate 374 * @param max 375 * - the max value to be used in Predicate 376 * @return the Predicate lesser or equals than this number, ignoring units 377 */ 378 public static <Q extends Quantity<Q>> Predicate<Quantity<Q>> isBetween(Number min, Number max) { 379 Predicate<Quantity<Q>> minFilter = isGreaterThanOrEqualTo(min); 380 Predicate<Quantity<Q>> maxFilter = isLesserThanOrEqualTo(max); 381 return minFilter.and(maxFilter); 382 } 383 384 /** 385 * creates a filter to between, lesser or equals and greater or equals, than the quantity measure 386 * 387 * @param min 388 * - the min value to be used in Predicate 389 * @param max 390 * - the max value to be used in Predicate 391 * @return the Predicate lesser or equals than this measure 392 */ 393 public static <Q extends Quantity<Q>> Predicate<Quantity<Q>> isBetween(Quantity<Q> min, Quantity<Q> max) { 394 return isGreaterThanOrEqualTo(min).and(isLesserThanOrEqualTo(max)); 395 } 396 397 /** 398 * Summary of Quantity 399 * 400 * @return the QuantitySummaryStatistics 401 */ 402 public static <Q extends Quantity<Q>> Collector<Quantity<Q>, QuantitySummaryStatistics<Q>, QuantitySummaryStatistics<Q>> summarizeQuantity( 403 Unit<Q> unit) { 404 Supplier<QuantitySummaryStatistics<Q>> supplier = () -> new QuantitySummaryStatistics<>(unit); 405 return Collector.of(supplier, QuantitySummaryStatistics<Q>::accept, QuantitySummaryStatistics<Q>::combine); 406 } 407 408 public static <Q extends Quantity<Q>> Function<Quantity<Q>, Unit<Q>> groupByUnit() { 409 return Quantity::getUnit; 410 } 411}