1 package org.djutils.exceptions;
2
3 import java.lang.reflect.Constructor;
4 import java.util.ArrayList;
5 import java.util.Arrays;
6 import java.util.IllegalFormatException;
7 import java.util.List;
8 import java.util.function.Supplier;
9
10 import org.djutils.reflection.ClassUtil;
11
12 /**
13 * The Throw class has a number of static methods that make it easy to throw an exception under conditions for any Exception
14 * class, including the standard Java exceptions and exceptions from libraries that are used in the project. Instead of:
15 *
16 * <pre>
17 * if (car == null)
18 * {
19 * throw new NullPointerException("Car may not be null.");
20 * }
21 * if (Double.isNaN(car.getPosition()))
22 * {
23 * throw new IllegalArgumentException("Position of car " + car + " is NaN.");
24 * }
25 * </pre>
26 *
27 * we can write:
28 *
29 * <pre>
30 * Throw.whenNull(car, "Car may not be null.");
31 * Throw.when(Double.isNaN(car.getPosition()), IllegalArgumentException.class, "Position of car %s is NaN.", car);
32 * </pre>
33 *
34 * The exception message can be formatted with additional arguments, such that the overhead of building the exception message
35 * only occurs if the exception condition is met. All methods have a version where the first parameter is returned. Thereby, the
36 * Throw can be used as part of a <b>super</b>(...) call in a constructor.
37 * <p>
38 * Copyright (c) 2016-2025 Delft University of Technology, Jaffalaan 5, 2628 BX Delft, the Netherlands. All rights reserved. See
39 * for project information <a href="https://djutils.org" target="_blank"> https://djutils.org</a>. The DJUTILS project is
40 * distributed under a three-clause BSD-style license, which can be found at
41 * <a href="https://djutils.org/docs/license.html" target="_blank"> https://djutils.org/docs/license.html</a>.
42 * </p>
43 * @author <a href="https://www.tudelft.nl/averbraeck">Alexander Verbraeck</a>
44 * @author <a href="https://www.tudelft.nl/staff/p.knoppers/">Peter Knoppers</a>
45 * @author <a href="http://www.transport.citg.tudelft.nl">Wouter Schakel</a>
46 */
47 @SuppressWarnings("checkstyle:linelength")
48 public final class Throw
49 {
50 /** private constructor for utility class. */
51 private Throw()
52 {
53 // utility class
54 }
55
56 /**
57 * Throw a Throwable (such as an Exception or Error) if a condition is met, e.g. for pre- and postcondition checking. Use as
58 * follows: <br>
59 *
60 * <pre>
61 * Throw.when(Double.isNan(object.getValue()), IllegalArgumentException.class, "Value may not be NaN.");
62 * </pre>
63 *
64 * @param condition the condition to check; an exception will be thrown if this is <b>true</b>
65 * @param throwableClass the Throwable type to throw
66 * @param message the message to use in the exception
67 * @throws T the throwable to throw on true condition
68 * @param <T> the Throwable type
69 */
70 public static <T extends Throwable> void when(final boolean condition, final Class<T> throwableClass, final String message)
71 throws T
72 {
73 if (condition)
74 {
75 throwMessage(throwableClass, message, null);
76 }
77 }
78
79 /**
80 * Throw a Throwable (such as an Exception or Error) if a condition is met, e.g. for pre- and postcondition checking. Use as
81 * follows: <br>
82 *
83 * <pre>
84 * Throw.when(Double.isNan(object.getValue()), IllegalArgumentException.class, () -> object.reportStatus());
85 * </pre>
86 *
87 * @param condition the condition to check; an exception will be thrown if this is <b>true</b>
88 * @param throwableClass the Throwable type to throw
89 * @param stringSupplier the supplier that provides the message to use in the exception
90 * @throws T the throwable to throw on true condition
91 * @param <T> the Throwable type
92 */
93 public static <T extends Throwable> void when(final boolean condition, final Class<T> throwableClass,
94 final Supplier<String> stringSupplier) throws T
95 {
96 if (condition)
97 {
98 throwMessage(throwableClass, stringSupplier.get(), null);
99 }
100 }
101
102 /**
103 * Throw a Throwable (such as an Exception or Error) if a condition is met, e.g. for pre- and postcondition checking. Use as
104 * follows: <br>
105 *
106 * <pre>
107 * Throw.when(Double.isNan(object.getValue()), IllegalArgumentException.class, "Value may not be NaN for object %s.", object);
108 * </pre>
109 *
110 * @param condition the condition to check; an exception will be thrown if this is <b>true</b>
111 * @param throwableClass the Throwable type to throw
112 * @param message the message to use in the exception, with formatting identifiers
113 * @param arg value to use for the formatting identifiers
114 * @throws T the throwable to throw on true condition
115 * @param <T> the Throwable type
116 */
117 public static <T extends Throwable> void when(final boolean condition, final Class<T> throwableClass, final String message,
118 final Object arg) throws T
119 {
120 if (condition)
121 {
122 List<Object> argList = new ArrayList<>();
123 argList.add(arg);
124 throwMessage(throwableClass, message, argList);
125 }
126 }
127
128 /**
129 * Throw a Throwable (such as an Exception or Error) if a condition is met, e.g. for pre- and postcondition checking. Use as
130 * follows: <br>
131 *
132 * <pre>
133 * Throw.when(Double.isNan(object.getValue()), IllegalArgumentException.class,
134 * "Value may not be NaN for object %s with name %s.", object, name);
135 * </pre>
136 *
137 * @param condition the condition to check; an exception will be thrown if this is <b>true</b>
138 * @param throwableClass the Throwable type to throw
139 * @param message the message to use in the exception, with formatting identifiers
140 * @param arg1 1st value to use for the formatting identifiers
141 * @param arg2 2nd value to use for the formatting identifiers
142 * @throws T the throwable to throw on true condition
143 * @param <T> the Throwable type
144 */
145 public static <T extends Throwable> void when(final boolean condition, final Class<T> throwableClass, final String message,
146 final Object arg1, final Object arg2) throws T
147 {
148 if (condition)
149 {
150 List<Object> argList = new ArrayList<>();
151 argList.add(arg1);
152 argList.add(arg2);
153 throwMessage(throwableClass, message, argList);
154 }
155 }
156
157 /**
158 * Throw a Throwable (such as an Exception or Error) if a condition is met, e.g. for pre- and postcondition checking. Use as
159 * follows: <br>
160 *
161 * <pre>
162 * Throw.when(Double.isNan(object.getValue()), IllegalArgumentException.class,
163 * "Value may not be NaN for object %s with name %s and id %s.", object, name, id);
164 * </pre>
165 *
166 * @param condition the condition to check; an exception will be thrown if this is <b>true</b>
167 * @param throwableClass the Throwable type to throw
168 * @param message the message to use in the exception, with formatting identifiers
169 * @param arg1 1st value to use for the formatting identifiers
170 * @param arg2 2nd value to use for the formatting identifiers
171 * @param arg3 3rd value to use for the formatting identifiers
172 * @throws T the throwable to throw on true condition
173 * @param <T> the Throwable type
174 */
175 public static <T extends Throwable> void when(final boolean condition, final Class<T> throwableClass, final String message,
176 final Object arg1, final Object arg2, final Object arg3) throws T
177 {
178 if (condition)
179 {
180 List<Object> argList = new ArrayList<>();
181 argList.add(arg1);
182 argList.add(arg2);
183 argList.add(arg3);
184 throwMessage(throwableClass, message, argList);
185 }
186 }
187
188 /**
189 * Throw a Throwable (such as an Exception or Error) if a condition is met, e.g. for pre- and postcondition checking. Use as
190 * follows: <br>
191 *
192 * <pre>
193 * Throw.when(Double.isNan(object.getValue()), IllegalArgumentException.class,
194 * "Value may not be NaN for object %s with name %s, id %s and parent %s.", object, name, id, parent);
195 * </pre>
196 *
197 * @param condition the condition to check; an exception will be thrown if this is <b>true</b>
198 * @param throwableClass the Throwable type to throw
199 * @param message the message to use in the exception, with formatting identifiers
200 * @param arg1 1st value to use for the formatting identifiers
201 * @param arg2 2nd value to use for the formatting identifiers
202 * @param arg3 3rd value to use for the formatting identifiers
203 * @param args potential 4th and further values to use for the formatting identifiers
204 * @throws T the throwable to throw on true condition
205 * @param <T> the Throwable type
206 */
207 public static <T extends Throwable> void when(final boolean condition, final Class<T> throwableClass, final String message,
208 final Object arg1, final Object arg2, final Object arg3, final Object... args) throws T
209 {
210 if (condition)
211 {
212 List<Object> argList = new ArrayList<>();
213 argList.add(arg1);
214 argList.add(arg2);
215 argList.add(arg3);
216 argList.addAll(Arrays.asList(args));
217 throwMessage(throwableClass, message, argList);
218 }
219 }
220
221 /**
222 * Private method to handle the throwing an Exception, Throwable or Error.
223 * @param throwableClass the Throwable type to throw
224 * @param message the message to use in the exception, with potential formatting identifiers
225 * @param argList List with potential values to use for the formatting identifiers, or null when there are no formatting
226 * identifiers
227 * @throws T the throwable to throw
228 * @param <T> the Throwable type
229 */
230 private static <T extends Throwable> void throwMessage(final Class<T> throwableClass, final String message,
231 final List<Object> argList) throws T
232 {
233 // create a clear message
234 List<StackTraceElement> steList = new ArrayList<>(Arrays.asList(new Throwable().getStackTrace()));
235 steList.remove(0); // remove the throwMessage(...) call
236 steList.remove(0); // remove the when(...) call
237 StackTraceElement[] ste = steList.toArray(new StackTraceElement[steList.size()]);
238 String where = ste[0].getClassName() + "." + ste[0].getMethodName() + " (" + ste[0].getLineNumber() + "): ";
239 String formattedMessage;
240 if (argList == null)
241 {
242 formattedMessage = message;
243 }
244 else
245 {
246 try
247 {
248 formattedMessage = where + String.format(message, argList.toArray());
249 }
250 catch (IllegalFormatException exception)
251 {
252 formattedMessage = where + message + " [FormatException; args=" + argList + "]";
253 }
254 }
255
256 // throw all other exceptions through reflection
257 T exception;
258 try
259 {
260 Constructor<T> constructor = ClassUtil.resolveConstructor(throwableClass, new Class<?>[] {String.class});
261 exception = constructor.newInstance(formattedMessage);
262 exception.setStackTrace(ste);
263 }
264 catch (Throwable t)
265 {
266 RuntimeException rte = new RuntimeException(t.getMessage(), new Exception(formattedMessage));
267 rte.setStackTrace(ste);
268 throw rte;
269 }
270 throw exception;
271 }
272
273 /**
274 * Throw a Throwable (such as an Exception or Error) if a condition is met, e.g. for pre- and postcondition checking. This
275 * version of the method returns its first parameter, so it can be used inside a constructor. Use e.g., as follows:
276 *
277 * <pre>
278 * super(Throw.when(object, Double.isNaN(object.getValue()), IllegalArgumentException.class, "Value may not be NaN."));
279 * </pre>
280 *
281 * @param object the object to return by this static method
282 * @param condition the condition to check; an exception will be thrown if this is <b>true</b>
283 * @param throwableClass the Throwable type to throw
284 * @param message the message to use in the exception
285 * @throws T the throwable to throw on true condition
286 * @param <T> the Throwable type
287 * @param <O> the Object type to return
288 * @return the object that was passed as the first parameter
289 */
290 public static <T extends Throwable, O extends Object> O when(final O object, final boolean condition,
291 final Class<T> throwableClass, final String message) throws T
292 {
293 if (condition)
294 {
295 throwMessage(throwableClass, message, null);
296 }
297 return object;
298 }
299
300 /**
301 * Throw a Throwable (such as an Exception or Error) if a condition is met, e.g. for pre- and postcondition checking. This
302 * version of the method returns its first parameter, so it can be used inside a constructor. Use e.g., as follows:
303 *
304 * <pre>
305 * super(Throw.when(object, object.isIncomplete(), IllegalArgumentException.class, () -> object.reportStatus()));
306 * </pre>
307 *
308 * @param object the object to return by this static method
309 * @param condition the condition to check; an exception will be thrown if this is <b>true</b>
310 * @param throwableClass the Throwable type to throw
311 * @param stringSupplier the supplier that provides the message to use in the exception
312 * @throws T the throwable to throw on true condition
313 * @param <T> the Throwable type
314 * @param <O> the Object type to return
315 * @return the object that was passed as the first parameter
316 */
317 public static <T extends Throwable, O extends Object> O when(final O object, final boolean condition,
318 final Class<T> throwableClass, final Supplier<String> stringSupplier) throws T
319 {
320 if (condition)
321 {
322 throwMessage(throwableClass, stringSupplier.get(), null);
323 }
324 return object;
325 }
326
327 /**
328 * Throw a Throwable (such as an Exception or Error) if a condition is met, e.g. for pre- and postcondition checking. This
329 * version of the method returns its first parameter, so it can be used inside a constructor. Use e.g., as follows:
330 *
331 * <pre>
332 * super(Throw.when(object, Double.isNan(object.getValue()), IllegalArgumentException.class,
333 * "Value may not be NaN for object %s.", object));
334 * </pre>
335 *
336 * @param object the object to return by this static method
337 * @param condition the condition to check; an exception will be thrown if this is <b>true</b>
338 * @param throwableClass the Throwable type to throw
339 * @param message the message to use in the exception, with formatting identifiers
340 * @param arg value to use for the formatting identifiers
341 * @throws T the throwable to throw on true condition
342 * @param <T> the Throwable type
343 * @param <O> the Object type to return
344 * @return the object that was passed as the first parameter
345 */
346 public static <T extends Throwable, O extends Object> O when(final O object, final boolean condition,
347 final Class<T> throwableClass, final String message, final Object arg) throws T
348 {
349 if (condition)
350 {
351 List<Object> argList = new ArrayList<>();
352 argList.add(arg);
353 throwMessage(throwableClass, message, argList);
354 }
355 return object;
356 }
357
358 /**
359 * Throw a Throwable (such as an Exception or Error) if a condition is met, e.g. for pre- and postcondition checking. This
360 * version of the method returns its first parameter, so it can be used inside a constructor. Use e.g., as follows:
361 *
362 * <pre>
363 * super(Throw.when(object, Double.isNan(object.getValue()), IllegalArgumentException.class,
364 * "Value may not be NaN for object %s with name %s.", object, name));
365 * </pre>
366 *
367 * @param object the object to return by this static method
368 * @param condition the condition to check; an exception will be thrown if this is <b>true</b>
369 * @param throwableClass the Throwable type to throw
370 * @param message the message to use in the exception, with formatting identifiers
371 * @param arg1 1st value to use for the formatting identifiers
372 * @param arg2 2nd value to use for the formatting identifiers
373 * @throws T the throwable to throw on true condition
374 * @param <T> the Throwable type
375 * @param <O> the Object type to return
376 * @return the object that was passed as the first parameter
377 */
378 public static <T extends Throwable, O extends Object> O when(final O object, final boolean condition,
379 final Class<T> throwableClass, final String message, final Object arg1, final Object arg2) throws T
380 {
381 if (condition)
382 {
383 List<Object> argList = new ArrayList<>();
384 argList.add(arg1);
385 argList.add(arg2);
386 throwMessage(throwableClass, message, argList);
387 }
388 return object;
389 }
390
391 /**
392 * Throw a Throwable (such as an Exception or Error) if a condition is met, e.g. for pre- and postcondition checking. This
393 * version of the method returns its first parameter, so it can be used inside a constructor. Use e.g., as follows:
394 *
395 * <pre>
396 * super(Throw.when(object, Double.isNan(object.getValue()), IllegalArgumentException.class,
397 * "Value may not be NaN for object %s with name %s and id %s.", object, name, id));
398 * </pre>
399 *
400 * @param object the object to return by this static method
401 * @param condition the condition to check; an exception will be thrown if this is <b>true</b>
402 * @param throwableClass the Throwable type to throw
403 * @param message the message to use in the exception, with formatting identifiers
404 * @param arg1 1st value to use for the formatting identifiers
405 * @param arg2 2nd value to use for the formatting identifiers
406 * @param arg3 3rd value to use for the formatting identifiers
407 * @throws T the throwable to throw on true condition
408 * @param <T> the Throwable type
409 * @param <O> the Object type to return
410 * @return the object that was passed as the first parameter
411 */
412 public static <T extends Throwable, O extends Object> O when(final O object, final boolean condition,
413 final Class<T> throwableClass, final String message, final Object arg1, final Object arg2, final Object arg3)
414 throws T
415 {
416 if (condition)
417 {
418 List<Object> argList = new ArrayList<>();
419 argList.add(arg1);
420 argList.add(arg2);
421 argList.add(arg3);
422 throwMessage(throwableClass, message, argList);
423 }
424 return object;
425 }
426
427 /**
428 * Throw a Throwable (such as an Exception or Error) if a condition is met, e.g. for pre- and postcondition checking. This
429 * version of the method returns its first parameter, so it can be used inside a constructor. Use e.g., as follows:
430 *
431 * <pre>
432 * super(Throw.when(object, Double.isNan(object.getValue()), IllegalArgumentException.class,
433 * "Value may not be NaN for object %s with name %s, id %s and parent %s.", object, name, id, parent));
434 * </pre>
435 *
436 * @param object the object to return by this static method
437 * @param condition the condition to check; an exception will be thrown if this is <b>true</b>
438 * @param throwableClass the Throwable type to throw
439 * @param message the message to use in the exception, with formatting identifiers
440 * @param arg1 1st value to use for the formatting identifiers
441 * @param arg2 2nd value to use for the formatting identifiers
442 * @param arg3 3rd value to use for the formatting identifiers
443 * @param args potential 4th and further values to use for the formatting identifiers
444 * @throws T the throwable to throw on true condition
445 * @param <T> the Throwable type
446 * @param <O> the Object type to return
447 * @return the object that was passed as the first parameter
448 */
449 @SuppressWarnings("checkstyle:parameternumber")
450 public static <T extends Throwable, O extends Object> O when(final O object, final boolean condition,
451 final Class<T> throwableClass, final String message, final Object arg1, final Object arg2, final Object arg3,
452 final Object... args) throws T
453 {
454 if (condition)
455 {
456 List<Object> argList = new ArrayList<>();
457 argList.add(arg1);
458 argList.add(arg2);
459 argList.add(arg3);
460 argList.addAll(Arrays.asList(args));
461 throwMessage(throwableClass, message, argList);
462 }
463 return object;
464 }
465
466 /**
467 * Throw a NullPointerException if object is null, e.g. for pre- and postcondition checking. Use as follows: <br>
468 *
469 * <pre>
470 * Throw.whenNull(value, "value may not be null.");
471 * </pre>
472 *
473 * A shortened version where the text " may not be null" is automatically appended after the variable name is just listing
474 * the variable name without any spaces:
475 *
476 * <pre>
477 * Throw.whenNull(value, "value");
478 * </pre>
479 *
480 * @param object an exception will be thrown if the object is <b>null</b>
481 * @param message the message to use in the exception, or the variable name that will be appended with " may not be null"
482 * @param <O> the Object type to return
483 * @return the object that was passed as the first parameter
484 * @throws NullPointerException if object is null
485 */
486 public static <O extends Object> O whenNull(final O object, final String message) throws NullPointerException
487 {
488 if (object == null)
489 {
490 if (message.matches("\\S+")) // \S+ is any non-whitespace character
491 {
492 throwMessage(NullPointerException.class, message + " may not be null", null);
493 }
494 else
495 {
496 throwMessage(NullPointerException.class, message, null);
497 }
498 }
499 return object;
500 }
501
502 /**
503 * Throw a NullPointerException if object is null, e.g. for pre- and postcondition checking. Use as follows: <br>
504 *
505 * <pre>
506 * Throw.whenNull(value, () -> getLocalizedNullMessage());
507 * </pre>
508 *
509 * @param object an exception will be thrown if the object is <b>null</b>
510 * @param stringSupplier the supplier that provides the message to use in the exception
511 * @param <O> the Object type to return
512 * @return the object that was passed as the first parameter
513 * @throws NullPointerException if object is null
514 */
515 public static <O extends Object> O whenNull(final O object, final Supplier<String> stringSupplier)
516 throws NullPointerException
517 {
518 if (object == null)
519 {
520 throwMessage(NullPointerException.class, stringSupplier.get(), null);
521 }
522 return object;
523 }
524
525 /**
526 * Throw a NullPointerException if object is null, e.g. for pre- and postcondition checking. Use as follows: <br>
527 *
528 * <pre>
529 * Throw.whenNull(object.getValue(), "Value may not be null for object %s.", object);
530 * </pre>
531 *
532 * @param object an exception will be thrown if this is <b>null</b>
533 * @param message the message to use in the exception, with formatting identifiers
534 * @param arg value to use for the formatting identifiers
535 * @param <O> the Object type to return
536 * @return the object that was passed as the first parameter
537 * @throws NullPointerException if object is null
538 */
539 public static <O extends Object> O whenNull(final O object, final String message, final Object arg)
540 throws NullPointerException
541 {
542 if (object == null)
543 {
544 List<Object> argList = new ArrayList<>();
545 argList.add(arg);
546 throwMessage(NullPointerException.class, message, argList);
547 }
548 return object;
549 }
550
551 /**
552 * Throw a NullPointerException if object is null, e.g. for pre- and postcondition checking. Use as follows: <br>
553 *
554 * <pre>
555 * Throw.whenNull(object.getValue(), "Value may not be null for object %s with name %s.", object, name);
556 * </pre>
557 *
558 * @param object an exception will be thrown if this is <b>null</b>
559 * @param message the message to use in the exception, with formatting identifiers
560 * @param arg1 1st value to use for the formatting identifiers
561 * @param arg2 2nd value to use for the formatting identifiers
562 * @param <O> the Object type to return
563 * @return the object that was passed as the first parameter
564 * @throws NullPointerException if object is null
565 */
566 public static <O extends Object> O whenNull(final O object, final String message, final Object arg1, final Object arg2)
567 throws NullPointerException
568 {
569 if (object == null)
570 {
571 List<Object> argList = new ArrayList<>();
572 argList.add(arg1);
573 argList.add(arg2);
574 throwMessage(NullPointerException.class, message, argList);
575 }
576 return object;
577 }
578
579 /**
580 * Throw a NullPointerException if object is null, e.g. for pre- and postcondition checking. Use as follows: <br>
581 *
582 * <pre>
583 * Throw.whenNull(object.getValue(), "Value may not be null for object %s with name %s and id %s.", object, name, id);
584 * </pre>
585 *
586 * @param object an exception will be thrown if this is <b>null</b>
587 * @param message the message to use in the exception, with formatting identifiers
588 * @param arg1 1st value to use for the formatting identifiers
589 * @param arg2 2nd value to use for the formatting identifiers
590 * @param arg3 3rd value to use for the formatting identifiers
591 * @param <O> the Object type to return
592 * @return the object that was passed as the first parameter
593 * @throws NullPointerException if object is null
594 */
595 public static <O extends Object> O whenNull(final O object, final String message, final Object arg1, final Object arg2,
596 final Object arg3) throws NullPointerException
597 {
598 if (object == null)
599 {
600 List<Object> argList = new ArrayList<>();
601 argList.add(arg1);
602 argList.add(arg2);
603 argList.add(arg3);
604 throwMessage(NullPointerException.class, message, argList);
605 }
606 return object;
607 }
608
609 /**
610 * Throw a NullPointerException if object is null, e.g. for pre- and postcondition checking. Use as follows: <br>
611 *
612 * <pre>
613 * Throw.whenNull(object.getValue(), "Value may not be null for object %s with name %s, id %s and parent %s.", object, name, id,
614 * parent);
615 * </pre>
616 *
617 * @param object an exception will be thrown if this is <b>null</b>
618 * @param message the message to use in the exception, with formatting identifiers
619 * @param arg1 1st value to use for the formatting identifiers
620 * @param arg2 2nd value to use for the formatting identifiers
621 * @param arg3 3rd value to use for the formatting identifiers
622 * @param args potential 4th and further values to use for the formatting identifiers
623 * @param <O> the Object type to return
624 * @return the object that was passed as the first parameter
625 * @throws NullPointerException if object is null
626 */
627 public static <O extends Object> O whenNull(final O object, final String message, final Object arg1, final Object arg2,
628 final Object arg3, final Object... args) throws NullPointerException
629 {
630 if (object == null)
631 {
632 List<Object> argList = new ArrayList<>();
633 argList.add(arg1);
634 argList.add(arg2);
635 argList.add(arg3);
636 argList.addAll(Arrays.asList(args));
637 throwMessage(NullPointerException.class, message, argList);
638 }
639 return object;
640 }
641
642 /**
643 * Throw a NullPointerException if any of the odd arguments is null, e.g. for pre- and postcondition checking. The message
644 * can consist of one identifier for the object, or a complete message. Use as follows: <br>
645 *
646 * <pre>
647 * Throw.whenAnyNull(alpha, "alpha", beta, "beta", calc, "the variable calc should not be null");
648 * </pre>
649 *
650 * @param object the first object to check
651 * @param message the message or id of the first object to check
652 * @param objects objects to check on the odd positions, and messages or ids for the objects on the even positions
653 * @throws IllegalArgumentException when the number of arguments is not even
654 * @throws IllegalArgumentException when any of the messages is null
655 * @throws NullPointerException if any of the objects to be tested is null
656 */
657 public static void whenAnyNull(final Object object, final String message, final Object... objects)
658 {
659 if ((objects.length & 1) == 1)
660 {
661 throw new IllegalArgumentException("Throw.whenAnyNull should have an even number of arguments");
662 }
663 if (message == null)
664 {
665 throw new IllegalArgumentException("Throw.whenAnyNull should not have any null message");
666 }
667 Throw.whenNull(object, message);
668 for (int i = 0; i < objects.length; i += 2)
669 {
670 if (objects[i + 1] == null)
671 {
672 throw new IllegalArgumentException("Throw.whenAnyNull should not have any null message");
673 }
674 Throw.whenNull(objects[i], objects[i + 1].toString());
675 }
676 }
677
678 /**
679 * Throw an ArithmeticException if value is NaN, e.g. for pre- and postcondition checking. Use as follows: <br>
680 *
681 * <pre>
682 * Throw.whenNaN(value, "value may not be NaN.");
683 * </pre>
684 *
685 * A shortened version where the text " may not be NaN" is automatically appended after the variable name is just listing
686 * the variable name without any spaces:
687 *
688 * <pre>
689 * Throw.whenNaN(value, "value");
690 * </pre>
691 *
692 * @param value value to check; an exception will be thrown if the object is <b>NaN</b>
693 * @param message the message to use in the exception, or the variable name that will be appended with " may not be NaN"
694 * @return the value that was passed as the first parameter
695 * @throws ArithmeticException if value is NaN
696 */
697 public static double whenNaN(final double value, final String message) throws ArithmeticException
698 {
699 if (Double.isNaN(value))
700 {
701 if (message.matches("\\S+")) // \S+ is any non-whitespace character
702 {
703 throwMessage(ArithmeticException.class, message + " may not be NaN", null);
704 }
705 else
706 {
707 throwMessage(ArithmeticException.class, message, null);
708 }
709 }
710 return value;
711 }
712
713 /**
714 * Throw an ArithmeticException if value is NaN, e.g. for pre- and postcondition checking. Use e.g. as follows: <br>
715 *
716 * <pre>
717 * Throw.whenNaN(value, () -> getLocalizedNaNMessage());
718 * </pre>
719 *
720 * @param value value to check; an exception will be thrown if the object is <b>NaN</b>
721 * @param stringSupplier the supplier that provides the message to use in the exception
722 * @return the value that was passed as the first parameter
723 * @throws ArithmeticException if value is NaN
724 */
725 public static double whenNaN(final double value, final Supplier<String> stringSupplier) throws ArithmeticException
726 {
727 if (Double.isNaN(value))
728 {
729 throwMessage(ArithmeticException.class, stringSupplier.get(), null);
730 }
731 return value;
732 }
733
734 /**
735 * Throw an ArithmeticException if value is NaN, e.g. for pre- and postcondition checking. Use as follows: <br>
736 *
737 * <pre>
738 * Throw.whenNaN(value, "value may not be NaN.");
739 * </pre>
740 *
741 * A shortened version where the text " may not be NaN" is automatically appended after the variable name is just listing
742 * the variable name without any spaces:
743 *
744 * <pre>
745 * Throw.whenNaN(value, "value");
746 * </pre>
747 *
748 * @param value value to check; an exception will be thrown if the object is <b>NaN</b>
749 * @param message the message to use in the exception, or the variable name that will be appended with " may not be NaN"
750 * @return the value that was passed as the first parameter
751 * @throws ArithmeticException if value is NaN
752 */
753 public static float whenNaN(final float value, final String message) throws ArithmeticException
754 {
755 if (Float.isNaN(value))
756 {
757 if (message.matches("\\S+")) // \S+ is any non-whitespace character
758 {
759 throwMessage(ArithmeticException.class, message + " may not be NaN", null);
760 }
761 else
762 {
763 throwMessage(ArithmeticException.class, message, null);
764 }
765 }
766 return value;
767 }
768
769 /**
770 * Throw an ArithmeticException if value is NaN, e.g. for pre- and postcondition checking. Use e.g. as follows: <br>
771 *
772 * <pre>
773 * Throw.whenNaN(value, () -> getLocalizedNaNMessage());
774 * </pre>
775 *
776 * @param value value to check; an exception will be thrown if the object is <b>NaN</b>
777 * @param stringSupplier the supplier that provides the message to use in the exception
778 * @return the value that was passed as the first parameter
779 * @throws ArithmeticException if value is NaN
780 */
781 public static float whenNaN(final float value, final Supplier<String> stringSupplier) throws ArithmeticException
782 {
783 if (Float.isNaN(value))
784 {
785 throwMessage(ArithmeticException.class, stringSupplier.get(), null);
786 }
787 return value;
788 }
789
790 /**
791 * Throw an ArithmeticException if value is NaN, e.g. for pre- and postcondition checking. Use as follows: <br>
792 *
793 * <pre>
794 * Throw.whenNaN(value, "value may not be NaN.");
795 * </pre>
796 *
797 * A shortened version where the text " may not be NaN" is automatically appended after the variable name is just listing
798 * the variable name without any spaces:
799 *
800 * <pre>
801 * Throw.whenNaN(value, "value");
802 * </pre>
803 *
804 * @param value value to check; an exception will be thrown if the object is <b>NaN</b>
805 * @param message the message to use in the exception, or the variable name that will be appended with " may not be NaN"
806 * @return the value that was passed as the first parameter
807 * @throws ArithmeticException if value is NaN
808 */
809 public static Double whenNaN(final Double value, final String message) throws ArithmeticException
810 {
811 if (value != null && Double.isNaN(value))
812 {
813 if (message.matches("\\S+")) // \S+ is any non-whitespace character
814 {
815 throwMessage(ArithmeticException.class, message + " may not be NaN", null);
816 }
817 else
818 {
819 throwMessage(ArithmeticException.class, message, null);
820 }
821 }
822 return value;
823 }
824
825 /**
826 * Throw an ArithmeticException if value is NaN, e.g. for pre- and postcondition checking. Use e.g. as follows: <br>
827 *
828 * <pre>
829 * Throw.whenNaN(value, () -> getLocalizedNaNMessage());
830 * </pre>
831 *
832 * @param value value to check; an exception will be thrown if the object is <b>NaN</b>
833 * @param stringSupplier the supplier that provides the message to use in the exception
834 * @return the value that was passed as the first parameter
835 * @throws ArithmeticException if value is NaN
836 */
837 public static Double whenNaN(final Double value, final Supplier<String> stringSupplier) throws ArithmeticException
838 {
839 if (value != null && Double.isNaN(value))
840 {
841 throwMessage(ArithmeticException.class, stringSupplier.get(), null);
842 }
843 return value;
844 }
845
846 /**
847 * Throw an ArithmeticException if value is NaN, e.g. for pre- and postcondition checking. Use as follows: <br>
848 *
849 * <pre>
850 * Throw.whenNaN(value, "value may not be NaN.");
851 * </pre>
852 *
853 * A shortened version where the text " may not be NaN" is automatically appended after the variable name is just listing
854 * the variable name without any spaces:
855 *
856 * <pre>
857 * Throw.whenNaN(value, "value");
858 * </pre>
859 *
860 * @param value value to check; an exception will be thrown if the object is <b>NaN</b>
861 * @param message the message to use in the exception, or the variable name that will be appended with " may not be NaN"
862 * @return the value that was passed as the first parameter
863 * @throws ArithmeticException if value is NaN
864 */
865 public static Float whenNaN(final Float value, final String message) throws ArithmeticException
866 {
867 if (value != null && Float.isNaN(value))
868 {
869 if (message.matches("\\S+")) // \S+ is any non-whitespace character
870 {
871 throwMessage(ArithmeticException.class, message + " may not be NaN", null);
872 }
873 else
874 {
875 throwMessage(ArithmeticException.class, message, null);
876 }
877 }
878 return value;
879 }
880
881 /**
882 * Throw an ArithmeticException if value is NaN, e.g. for pre- and postcondition checking. Use e.g. as follows: <br>
883 *
884 * <pre>
885 * Throw.whenNaN(value, () -> getLocalizedNaNMessage());
886 * </pre>
887 *
888 * @param value value to check; an exception will be thrown if the object is <b>NaN</b>
889 * @param stringSupplier the supplier that provides the message to use in the exception
890 * @return the value that was passed as the first parameter
891 * @throws ArithmeticException if value is NaN
892 */
893 public static Float whenNaN(final Float value, final Supplier<String> stringSupplier) throws ArithmeticException
894 {
895 if (value != null && Float.isNaN(value))
896 {
897 throwMessage(ArithmeticException.class, stringSupplier.get(), null);
898 }
899 return value;
900 }
901
902 /**
903 * Throw an ArithmeticException if value is NaN, e.g. for pre- and postcondition checking. Use as follows: <br>
904 *
905 * <pre>
906 * Throw.whenNaN(value, "Value may not be NaN for object %s with name %s, id %s.", object, name, id);
907 * </pre>
908 *
909 * @param value the value to check; an exception will be thrown if this is <b>NaN</b>
910 * @param message the message to use in the exception, with formatting identifiers
911 * @param arg1 1st value to use for the formatting identifiers
912 * @param args potential 2nd and further values to use for the formatting identifiers
913 * @return the value that was passed as the first parameter
914 * @throws ArithmeticException if value is NaN
915 */
916 public static Double whenNaN(final Double value, final String message, final Object arg1, final Object... args)
917 throws ArithmeticException
918 {
919 if (value != null && Double.isNaN(value))
920 {
921 List<Object> argList = new ArrayList<>();
922 argList.add(arg1);
923 argList.addAll(Arrays.asList(args));
924 throwMessage(ArithmeticException.class, message, argList);
925 }
926 return value;
927 }
928
929 /**
930 * Throw an ArithmeticException if value is NaN, e.g. for pre- and postcondition checking. Use as follows: <br>
931 *
932 * <pre>
933 * Throw.whenNaN(value, "Value may not be NaN for object %s with name %s, id %s.", object, name, id);
934 * </pre>
935 *
936 * @param value the value to check; an exception will be thrown if this is <b>NaN</b>
937 * @param message the message to use in the exception, with formatting identifiers
938 * @param arg1 1st value to use for the formatting identifiers
939 * @param args potential 2nd and further values to use for the formatting identifiers
940 * @return the value that was passed as the first parameter
941 * @throws ArithmeticException if value is NaN
942 */
943 public static Float whenNaN(final Float value, final String message, final Object arg1, final Object... args)
944 throws ArithmeticException
945 {
946 if (value != null && Float.isNaN(value))
947 {
948 List<Object> argList = new ArrayList<>();
949 argList.add(arg1);
950 argList.addAll(Arrays.asList(args));
951 throwMessage(ArithmeticException.class, message, argList);
952 }
953 return value;
954 }
955
956 /**
957 * Throw a specified exception if value is NaN, e.g. for pre- and postcondition checking. Use as follows: <br>
958 *
959 * <pre>
960 * Throw.whenNaN(value, IllegalArgumentException.class, "value may not be NaN.");
961 * </pre>
962 *
963 * A shortened version where the text " may not be NaN" is automatically appended after the variable name is just listing
964 * the variable name without any spaces:
965 *
966 * <pre>
967 * Throw.whenNaN(value, IllegalArgumentException.class, "value");
968 * </pre>
969 *
970 * @param value value to check; an exception will be thrown if the object is <b>NaN</b>
971 * @param throwableClass the Throwable type to throw
972 * @param message the message to use in the exception, or the variable name that will be appended with " may not be NaN"
973 * @param <T> the Throwable class
974 * @return the value that was passed as the first parameter
975 * @throws T if value is NaN
976 */
977 public static <T extends Throwable> double whenNaN(final double value, final Class<T> throwableClass, final String message)
978 throws T
979 {
980 if (Double.isNaN(value))
981 {
982 if (message.matches("\\S+")) // \S+ is any non-whitespace character
983 {
984 throwMessage(throwableClass, message + " may not be NaN", null);
985 }
986 else
987 {
988 throwMessage(throwableClass, message, null);
989 }
990 }
991 return value;
992 }
993
994 /**
995 * Throw a specified exception if value is NaN, e.g. for pre- and postcondition checking. Use as follows: <br>
996 *
997 * <pre>
998 * Throw.whenNaN(value, IllegalArgumentException.class, "value may not be NaN.");
999 * </pre>
1000 *
1001 * A shortened version where the text " may not be NaN" is automatically appended after the variable name is just listing
1002 * the variable name without any spaces:
1003 *
1004 * <pre>
1005 * Throw.whenNaN(value, IllegalArgumentException.class, "value");
1006 * </pre>
1007 *
1008 * @param value value to check; an exception will be thrown if the object is <b>NaN</b>
1009 * @param throwableClass the Throwable type to throw
1010 * @param message the message to use in the exception, or the variable name that will be appended with " may not be NaN"
1011 * @param <T> the Throwable class
1012 * @return the value that was passed as the first parameter
1013 * @throws T if value is NaN
1014 */
1015 public static <T extends Throwable> float whenNaN(final float value, final Class<T> throwableClass, final String message)
1016 throws T
1017 {
1018 if (Float.isNaN(value))
1019 {
1020 if (message.matches("\\S+")) // \S+ is any non-whitespace character
1021 {
1022 throwMessage(throwableClass, message + " may not be NaN", null);
1023 }
1024 else
1025 {
1026 throwMessage(throwableClass, message, null);
1027 }
1028 }
1029 return value;
1030 }
1031
1032 /**
1033 * Throw a specified exception if value is NaN, e.g. for pre- and postcondition checking. Use as follows: <br>
1034 *
1035 * <pre>
1036 * Throw.whenNaN(value, IllegalArgumentException.class, () -> getLocalizedNaNMessage());
1037 * </pre>
1038 *
1039 * @param value value to check; an exception will be thrown if the object is <b>NaN</b>
1040 * @param throwableClass the Throwable type to throw
1041 * @param stringSupplier the supplier that provides the message to use in the exception
1042 * @param <T> the Throwable class
1043 * @return the value that was passed as the first parameter
1044 * @throws T if value is NaN
1045 */
1046 public static <T extends Throwable> float whenNaN(final float value, final Class<T> throwableClass,
1047 final Supplier<String> stringSupplier) throws T
1048 {
1049 if (Float.isNaN(value))
1050 {
1051 throwMessage(throwableClass, stringSupplier.get(), null);
1052 }
1053 return value;
1054 }
1055
1056 /**
1057 * Throw a specified exception if value is NaN, e.g. for pre- and postcondition checking. Use as follows: <br>
1058 *
1059 * <pre>
1060 * Throw.whenNaN(value, IllegalArgumentException.class, "value may not be NaN.");
1061 * </pre>
1062 *
1063 * A shortened version where the text " may not be NaN" is automatically appended after the variable name is just listing
1064 * the variable name without any spaces:
1065 *
1066 * <pre>
1067 * Throw.whenNaN(value, IllegalArgumentException.class, "value");
1068 * </pre>
1069 *
1070 * @param value value to check; an exception will be thrown if the object is <b>NaN</b>
1071 * @param throwableClass the Throwable type to throw
1072 * @param message the message to use in the exception, or the variable name that will be appended with " may not be NaN"
1073 * @param <T> the Throwable class
1074 * @return the value that was passed as the first parameter
1075 * @throws T if value is NaN
1076 */
1077 public static <T extends Throwable> Double whenNaN(final Double value, final Class<T> throwableClass, final String message)
1078 throws T
1079 {
1080 if (value != null && Double.isNaN(value))
1081 {
1082 if (message.matches("\\S+")) // \S+ is any non-whitespace character
1083 {
1084 throwMessage(throwableClass, message + " may not be NaN", null);
1085 }
1086 else
1087 {
1088 throwMessage(throwableClass, message, null);
1089 }
1090 }
1091 return value;
1092 }
1093
1094 /**
1095 * Throw a specified exception if value is NaN, e.g. for pre- and postcondition checking. Use as follows: <br>
1096 *
1097 * <pre>
1098 * Throw.whenNaN(value, IllegalArgumentException.class, () -> getLocalizedNaNMessage());
1099 * </pre>
1100 *
1101 * @param value value to check; an exception will be thrown if the object is <b>NaN</b>
1102 * @param throwableClass the Throwable type to throw
1103 * @param stringSupplier the supplier that provides the message to use in the exception
1104 * @param <T> the Throwable class
1105 * @return the value that was passed as the first parameter
1106 * @throws T if value is NaN
1107 */
1108 public static <T extends Throwable> double whenNaN(final double value, final Class<T> throwableClass,
1109 final Supplier<String> stringSupplier) throws T
1110 {
1111 if (Double.isNaN(value))
1112 {
1113 throwMessage(throwableClass, stringSupplier.get(), null);
1114 }
1115 return value;
1116 }
1117
1118 /**
1119 * Throw a specified exception if value is NaN, e.g. for pre- and postcondition checking. Use as follows: <br>
1120 *
1121 * <pre>
1122 * Throw.whenNaN(value, IllegalArgumentException.class, () -> getLocalizedNaNMessage());
1123 * </pre>
1124 *
1125 * @param value value to check; an exception will be thrown if the object is <b>NaN</b>
1126 * @param throwableClass the Throwable type to throw
1127 * @param stringSupplier the supplier that provides the message to use in the exception
1128 * @param <T> the Throwable class
1129 * @return the value that was passed as the first parameter
1130 * @throws T if value is NaN
1131 */
1132 public static <T extends Throwable> Double whenNaN(final Double value, final Class<T> throwableClass,
1133 final Supplier<String> stringSupplier) throws T
1134 {
1135 if (value != null && Double.isNaN(value))
1136 {
1137 throwMessage(throwableClass, stringSupplier.get(), null);
1138 }
1139 return value;
1140 }
1141
1142 /**
1143 * Throw a specified exception if value is NaN, e.g. for pre- and postcondition checking. Use as follows: <br>
1144 *
1145 * <pre>
1146 * Throw.whenNaN(value, IllegalArgumentException.class, "Value may not be NaN for object %s with name %s,
1147 * id %s.", object, name, id);
1148 * </pre>
1149 *
1150 * @param value the value to check; an exception will be thrown if this is <b>NaN</b>
1151 * @param throwableClass the Throwable type to throw
1152 * @param message the message to use in the exception, with formatting identifiers
1153 * @param arg1 1st value to use for the formatting identifiers
1154 * @param args potential 2nd and further values to use for the formatting identifiers
1155 * @param <T> the Throwable class
1156 * @return the value that was passed as the first parameter
1157 * @throws T if value is NaN
1158 */
1159 public static <T extends Throwable> Double whenNaN(final Double value, final Class<T> throwableClass, final String message,
1160 final Object arg1, final Object... args) throws T
1161 {
1162 if (value != null && Double.isNaN(value))
1163 {
1164 List<Object> argList = new ArrayList<>();
1165 argList.add(arg1);
1166 argList.addAll(Arrays.asList(args));
1167 throwMessage(throwableClass, message, argList);
1168 }
1169 return value;
1170 }
1171
1172 /**
1173 * Throw a specified exception if value is NaN, e.g. for pre- and postcondition checking. Use as follows: <br>
1174 *
1175 * <pre>
1176 * Throw.whenNaN(value, IllegalArgumentException.class, "value may not be NaN.");
1177 * </pre>
1178 *
1179 * A shortened version where the text " may not be NaN" is automatically appended after the variable name is just listing
1180 * the variable name without any spaces:
1181 *
1182 * <pre>
1183 * Throw.whenNaN(value, IllegalArgumentException.class, "value");
1184 * </pre>
1185 *
1186 * @param value value to check; an exception will be thrown if the object is <b>NaN</b>
1187 * @param throwableClass the Throwable type to throw
1188 * @param message the message to use in the exception, or the variable name that will be appended with " may not be NaN"
1189 * @param <T> the Throwable class
1190 * @return the value that was passed as the first parameter
1191 * @throws T if value is NaN
1192 */
1193 public static <T extends Throwable> Float whenNaN(final Float value, final Class<T> throwableClass, final String message)
1194 throws T
1195 {
1196 if (value != null && Float.isNaN(value))
1197 {
1198 if (message.matches("\\S+")) // \S+ is any non-whitespace character
1199 {
1200 throwMessage(throwableClass, message + " may not be NaN", null);
1201 }
1202 else
1203 {
1204 throwMessage(throwableClass, message, null);
1205 }
1206 }
1207 return value;
1208 }
1209
1210 /**
1211 * Throw a specified exception if value is NaN, e.g. for pre- and postcondition checking. Use as follows: <br>
1212 *
1213 * <pre>
1214 * Throw.whenNaN(value, IllegalArgumentException.class, () -> getLocalizedNaNMessage());
1215 * </pre>
1216 *
1217 * @param value value to check; an exception will be thrown if the object is <b>NaN</b>
1218 * @param throwableClass the Throwable type to throw
1219 * @param stringSupplier the supplier that provides the message to use in the exception
1220 * @param <T> the Throwable class
1221 * @return the value that was passed as the first parameter
1222 * @throws T if value is NaN
1223 */
1224 public static <T extends Throwable> Float whenNaN(final Float value, final Class<T> throwableClass,
1225 final Supplier<String> stringSupplier) throws T
1226 {
1227 if (value != null && Float.isNaN(value))
1228 {
1229 throwMessage(throwableClass, stringSupplier.get(), null);
1230 }
1231 return value;
1232 }
1233
1234 /**
1235 * Throw a specified exception if value is NaN, e.g. for pre- and postcondition checking. Use as follows: <br>
1236 *
1237 * <pre>
1238 * Throw.whenNaN(value, IllegalArgumentException.class, "Value may not be NaN for object %s with name %s,
1239 * id %s.", object, name, id);
1240 * </pre>
1241 *
1242 * @param value the value to check; an exception will be thrown if this is <b>NaN</b>
1243 * @param throwableClass the Throwable type to throw
1244 * @param message the message to use in the exception, with formatting identifiers
1245 * @param arg1 1st value to use for the formatting identifiers
1246 * @param args potential 2nd and further values to use for the formatting identifiers
1247 * @param <T> the Throwable class
1248 * @return the value that was passed as the first parameter
1249 * @throws T if value is NaN
1250 */
1251 public static <T extends Throwable> Float whenNaN(final Float value, final Class<T> throwableClass, final String message,
1252 final Object arg1, final Object... args) throws T
1253 {
1254 if (value != null && Float.isNaN(value))
1255 {
1256 List<Object> argList = new ArrayList<>();
1257 argList.add(arg1);
1258 argList.addAll(Arrays.asList(args));
1259 throwMessage(throwableClass, message, argList);
1260 }
1261 return value;
1262 }
1263
1264 /**
1265 * Throw an unchecked exception for a method with a fixed signature (e.g., extending a method from a library that cannot be
1266 * changed), without having to declare the exception, which can be impossible when extending a method. The typical use is:
1267 *
1268 * <pre>
1269 * @Override
1270 * public void someMethod() {
1271 * try {
1272 * // some code that throws e.g., an IOException
1273 * } catch IOException e {
1274 * Throw.throwUnchecked(e);
1275 * }
1276 * }
1277 * </pre>
1278 *
1279 * From: <a href="http://blog.ragozin.info/2011/10/java-how-to-throw-undeclared-checked.html" target="_blank">
1280 * http://blog.ragozin.info/2011/10/java-how-to-throw-undeclared-checked.html</a> as mentioned in <a href=
1281 * "https://stackoverflow.com/questions/11942946/how-to-throw-an-exception-when-your-method-signature-doesnt-allow-to-throw-exce"
1282 * target="_blank">
1283 * https://stackoverflow.com/questions/11942946/how-to-throw-an-exception-when-your-method-signature-doesnt-allow-to-throw-exce</a>.
1284 * @param e the exception of Throwable to throw in an unchecked manner
1285 */
1286 @SuppressWarnings("checkstyle:genericwhitespace")
1287 public static void throwUnchecked(final Throwable e)
1288 {
1289 Throw.<RuntimeException> throwAny(e);
1290 }
1291
1292 /**
1293 * @param <E> The exception class
1294 * @param e The throwable
1295 * @throws E The exception to throw
1296 */
1297 @SuppressWarnings("unchecked")
1298 private static <E extends Throwable> void throwAny(final Throwable e) throws E
1299 {
1300 throw (E) e;
1301 }
1302 }