View Javadoc
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   
9   import org.djutils.reflection.ClassUtil;
10  
11  /**
12   * The Try class has a number of static methods that make it easy to try-catch an exception for any Throwable class, including
13   * the standard Java exceptions and exceptions from libraries that are used in the project. Instead of:
14   * 
15   * <pre>
16   * FileInputStream fis;
17   * try
18   * {
19   *     fis = new FileInputStream(fileString);
20   * }
21   * catch (FileNotFoundException exception)
22   * {
23   *     throw new IllegalArgumentException("File " + fileString + " is not a valid file.", exception);
24   * }
25   * try
26   * {
27   *     fis.close();
28   * }
29   * catch (IOException exception)
30   * {
31   *     throw new RuntimeException("Could not close the file.", exception);
32   * }
33   * </pre>
34   * 
35   * we can write:
36   * 
37   * <pre>
38   * FileInputStream fis = Try.assign(() -&gt; new FileInputStream(fileString), IllegalArgumentException.class,
39   *         "File %s is not a valid file.", fileString);
40   * Try.execute(() -&gt; fis.close(), "Could not close the file.");
41   * </pre>
42   * 
43   * The exception message can be formatted with additional arguments, such that the overhead of building the exception message
44   * only occurs if the exception condition is met. For each method there is a version without Throwable class, in which case a
45   * RuntimeException will be thrown.<br>
46   * <br>
47   * Try is not suitable for try-with-resource statements.<br>
48   * <br>
49   * Try also has a few methods to aid JUNIT tests: {@code testFail(...)} and {@code testNotFail(...)}.
50   * <p>
51   * Copyright (c) 2016-2021 Delft University of Technology, Jaffalaan 5, 2628 BX Delft, the Netherlands. All rights reserved. See
52   * for project information <a href="https://djutils.org" target="_blank"> https://djutils.org</a>. The DJUTILS project is
53   * distributed under a three-clause BSD-style license, which can be found at
54   * <a href="https://djutils.org/docs/license.html" target="_blank"> https://djutils.org/docs/license.html</a>.
55   * </p>
56   * @author <a href="https://www.tudelft.nl/averbraeck">Alexander Verbraeck</a>
57   * @author <a href="https://www.tudelft.nl/staff/p.knoppers/">Peter Knoppers</a>
58   * @author <a href="http://www.transport.citg.tudelft.nl">Wouter Schakel</a>
59   */
60  public final class Try
61  {
62      /** private constructor for utility class. */
63      private Try()
64      {
65          // utility class
66      }
67  
68      // Assign
69  
70      /**
71       * Tries to return a value to assign. Will throw a RuntimeException if the try fails.
72       * @param assignment Assignment&lt;V&gt;; functional interface to assign value
73       * @param message String; the message to use in the throwable
74       * @param <V> value type
75       * @return V; value to assign
76       * @throws RuntimeException on failed Try
77       */
78      public static <V> V assign(final Assignment<V> assignment, final String message) throws RuntimeException
79      {
80          try
81          {
82              return assignment.assign();
83          }
84          catch (Throwable cause)
85          {
86              throw catchThrowable(RuntimeException.class, message, new ArrayList<>(), cause);
87          }
88      }
89  
90      /**
91       * Tries to return a value to assign. Will throw a RuntimeException if the try fails.
92       * @param assignment Assignment&lt;V&gt;; functional interface to assign value
93       * @param message String; the message to use in the throwable, with formatting identifier
94       * @param arg Object; value to use for the formatting identifier
95       * @param <V> value type
96       * @return V; value to assign
97       * @throws RuntimeException on failed Try
98       */
99      public static <V> V assign(final Assignment<V> assignment, final String message, final Object arg) throws RuntimeException
100     {
101         try
102         {
103             return assignment.assign();
104         }
105         catch (Throwable cause)
106         {
107             List<Object> argList = new ArrayList<>();
108             argList.add(arg);
109             throw catchThrowable(RuntimeException.class, message, argList, cause);
110         }
111     }
112 
113     /**
114      * Tries to return a value to assign. Will throw a RuntimeException if the try fails.
115      * @param assignment Assignment&lt;V&gt;; functional interface to assign value
116      * @param message String; the message to use in the throwable, with formatting identifiers
117      * @param arg1 Object; 1st value to use for the formatting identifiers
118      * @param arg2 Object; 2nd value to use for the formatting identifiers
119      * @param <V> value type
120      * @return V; value to assign
121      * @throws RuntimeException on failed Try
122      */
123     public static <V> V assign(final Assignment<V> assignment, final String message, final Object arg1, final Object arg2)
124             throws RuntimeException
125     {
126         try
127         {
128             return assignment.assign();
129         }
130         catch (Throwable cause)
131         {
132             List<Object> argList = new ArrayList<>();
133             argList.add(arg1);
134             argList.add(arg2);
135             throw catchThrowable(RuntimeException.class, message, argList, cause);
136         }
137     }
138 
139     /**
140      * Tries to return a value to assign. Will throw a RuntimeException if the try fails.
141      * @param assignment Assignment&lt;V&gt;; functional interface to assign value
142      * @param message String; the message to use in the throwable, with formatting identifiers
143      * @param arg1 Object; 1st value to use for the formatting identifiers
144      * @param arg2 Object; 2nd value to use for the formatting identifiers
145      * @param arg3 Object; 3rd value to use for the formatting identifiers
146      * @param <V> value type
147      * @return V; value to assign
148      * @throws RuntimeException on failed Try
149      */
150     public static <V> V assign(final Assignment<V> assignment, final String message, final Object arg1, final Object arg2,
151             final Object arg3) throws RuntimeException
152     {
153         try
154         {
155             return assignment.assign();
156         }
157         catch (Throwable cause)
158         {
159             List<Object> argList = new ArrayList<>();
160             argList.add(arg1);
161             argList.add(arg2);
162             argList.add(arg3);
163             throw catchThrowable(RuntimeException.class, message, argList, cause);
164         }
165     }
166 
167     /**
168      * Tries to return a value to assign. Will throw a RuntimeException if the try fails.
169      * @param assignment Assignment&lt;V&gt;; functional interface to assign value
170      * @param message String; the message to use in the throwable, with formatting identifiers
171      * @param arg1 Object; 1st value to use for the formatting identifiers
172      * @param arg2 Object; 2nd value to use for the formatting identifiers
173      * @param arg3 Object; 3rd value to use for the formatting identifiers
174      * @param args Object...; potential 4th and further values to use for the formatting identifiers
175      * @param <V> value type
176      * @return V; value to assign
177      * @throws RuntimeException on failed Try
178      */
179     public static <V> V assign(final Assignment<V> assignment, final String message, final Object arg1, final Object arg2,
180             final Object arg3, final Object... args) throws RuntimeException
181     {
182         try
183         {
184             return assignment.assign();
185         }
186         catch (Throwable cause)
187         {
188             List<Object> argList = new ArrayList<>();
189             argList.add(arg1);
190             argList.add(arg2);
191             argList.add(arg3);
192             argList.addAll(Arrays.asList(args));
193             throw catchThrowable(RuntimeException.class, message, argList, cause);
194         }
195     }
196 
197     /**
198      * Tries to return a value to assign. Will throw a specified Throwable if the try fails.
199      * @param assignment Assignment&lt;V&gt;; functional interface to assign value
200      * @param throwableClass Class&lt;T&gt;; class of the throwable to throw
201      * @param message String; the message to use in the throwable
202      * @param <V> value type
203      * @param <T> throwable type
204      * @return V; value to assign
205      * @throws T throwable on failed Try
206      */
207     public static <V, T extends Throwable> V assign(final Assignment<V> assignment, final Class<T> throwableClass,
208             final String message) throws T
209     {
210         try
211         {
212             return assignment.assign();
213         }
214         catch (Throwable cause)
215         {
216             throw catchThrowable(throwableClass, message, new ArrayList<>(), cause);
217         }
218     }
219 
220     /**
221      * Tries to return a value to assign. Will throw a specified Throwable if the try fails.
222      * @param assignment Assignment&lt;V&gt;; functional interface to assign value
223      * @param throwableClass Class&lt;T&gt;; class of the throwable to throw
224      * @param message String; the message to use in the throwable, with formatting identifier
225      * @param arg Object; value to use for the formatting identifier
226      * @param <V> value type
227      * @param <T> throwable type
228      * @return V; value to assign
229      * @throws T throwable on failed Try
230      */
231     public static <V, T extends Throwable> V assign(final Assignment<V> assignment, final Class<T> throwableClass,
232             final String message, final Object arg) throws T
233     {
234         try
235         {
236             return assignment.assign();
237         }
238         catch (Throwable cause)
239         {
240             List<Object> argList = new ArrayList<>();
241             argList.add(arg);
242             throw catchThrowable(throwableClass, message, argList, cause);
243         }
244     }
245 
246     /**
247      * Tries to return a value to assign. Will throw a specified Throwable if the try fails.
248      * @param assignment Assignment&lt;V&gt;; functional interface to assign value
249      * @param throwableClass Class&lt;T&gt;; class of the throwable to throw
250      * @param message String; the message to use in the throwable, with formatting identifiers
251      * @param arg1 Object; 1st value to use for the formatting identifiers
252      * @param arg2 Object; 2nd value to use for the formatting identifiers
253      * @param <V> value type
254      * @param <T> throwable type
255      * @return V; value to assign
256      * @throws T throwable on failed Try
257      */
258     public static <V, T extends Throwable> V assign(final Assignment<V> assignment, final Class<T> throwableClass,
259             final String message, final Object arg1, final Object arg2) throws T
260     {
261         try
262         {
263             return assignment.assign();
264         }
265         catch (Throwable cause)
266         {
267             List<Object> argList = new ArrayList<>();
268             argList.add(arg1);
269             argList.add(arg2);
270             throw catchThrowable(throwableClass, message, argList, cause);
271         }
272     }
273 
274     /**
275      * Tries to return a value to assign. Will throw a specified Throwable if the try fails.
276      * @param assignment Assignment&lt;V&gt;; functional interface to assign value
277      * @param throwableClass Class&lt;T&gt;; class of the throwable to throw
278      * @param message String; the message to use in the throwable, with formatting identifiers
279      * @param arg1 Object; 1st value to use for the formatting identifiers
280      * @param arg2 Object; 2nd value to use for the formatting identifiers
281      * @param arg3 Object; 3rd value to use for the formatting identifiers
282      * @param <V> value type
283      * @param <T> throwable type
284      * @return V; value to assign
285      * @throws T throwable on failed Try
286      */
287     public static <V, T extends Throwable> V assign(final Assignment<V> assignment, final Class<T> throwableClass,
288             final String message, final Object arg1, final Object arg2, final Object arg3) throws T
289     {
290         try
291         {
292             return assignment.assign();
293         }
294         catch (Throwable cause)
295         {
296             List<Object> argList = new ArrayList<>();
297             argList.add(arg1);
298             argList.add(arg2);
299             argList.add(arg3);
300             throw catchThrowable(throwableClass, message, argList, cause);
301         }
302     }
303 
304     /**
305      * Tries to return a value to assign. Will throw a specified Throwable if the try fails.
306      * @param assignment Assignment&lt;V&gt;; functional interface to assign value
307      * @param throwableClass Class&lt;T&gt;; class of the throwable to throw
308      * @param message String; the message to use in the throwable, with formatting identifiers
309      * @param arg1 Object; 1st value to use for the formatting identifiers
310      * @param arg2 Object; 2nd value to use for the formatting identifiers
311      * @param arg3 Object; 3rd value to use for the formatting identifiers
312      * @param args Object...; potential 4th and further values to use for the formatting identifiers
313      * @param <V> value type
314      * @param <T> throwable type
315      * @return V; value to assign
316      * @throws T throwable on failed Try
317      */
318     public static <V, T extends Throwable> V assign(final Assignment<V> assignment, final Class<T> throwableClass,
319             final String message, final Object arg1, final Object arg2, final Object arg3, final Object... args) throws T
320     {
321         try
322         {
323             return assignment.assign();
324         }
325         catch (Throwable cause)
326         {
327             List<Object> argList = new ArrayList<>();
328             argList.add(arg1);
329             argList.add(arg2);
330             argList.add(arg3);
331             argList.addAll(Arrays.asList(args));
332             throw catchThrowable(throwableClass, message, argList, cause);
333         }
334     }
335 
336     // Execute
337 
338     /**
339      * Tries to execute. Will throw a RuntimeException if the try fails.
340      * @param execution Execution; functional interface to execute
341      * @param message String; the message to use in the throwable
342      * @throws RuntimeException on failed Try
343      */
344     public static void execute(final Execution execution, final String message) throws RuntimeException
345     {
346         try
347         {
348             execution.execute();
349         }
350         catch (Throwable cause)
351         {
352             throw catchThrowable(RuntimeException.class, message, new ArrayList<>(), cause);
353         }
354     }
355 
356     /**
357      * Tries to execute. Will throw a RuntimeException if the try fails.
358      * @param execution Execution; functional interface to execute
359      * @param message String; the message to use in the throwable, with formatting identifier
360      * @param arg Object; value to use for the formatting identifier
361      * @throws RuntimeException on failed Try
362      */
363     public static void execute(final Execution execution, final String message, final Object arg) throws RuntimeException
364     {
365         try
366         {
367             execution.execute();
368         }
369         catch (Throwable cause)
370         {
371             List<Object> argList = new ArrayList<>();
372             argList.add(arg);
373             throw catchThrowable(RuntimeException.class, message, argList, cause);
374         }
375     }
376 
377     /**
378      * Tries to execute. Will throw a RuntimeException if the try fails.
379      * @param execution Execution; functional interface to execute
380      * @param message String; the message to use in the throwable, with formatting identifiers
381      * @param arg1 Object; 1st value to use for the formatting identifiers
382      * @param arg2 Object; 2nd value to use for the formatting identifiers
383      * @throws RuntimeException on failed Try
384      */
385     public static void execute(final Execution execution, final String message, final Object arg1, final Object arg2)
386             throws RuntimeException
387     {
388         try
389         {
390             execution.execute();
391         }
392         catch (Throwable cause)
393         {
394             List<Object> argList = new ArrayList<>();
395             argList.add(arg1);
396             argList.add(arg2);
397             throw catchThrowable(RuntimeException.class, message, argList, cause);
398         }
399     }
400 
401     /**
402      * Tries to execute. Will throw a RuntimeException if the try fails.
403      * @param execution Execution; functional interface to execute
404      * @param message String; the message to use in the throwable, with formatting identifiers
405      * @param arg1 Object; 1st value to use for the formatting identifiers
406      * @param arg2 Object; 2nd value to use for the formatting identifiers
407      * @param arg3 Object; 3rd value to use for the formatting identifiers
408      * @throws RuntimeException on failed Try
409      */
410     public static void execute(final Execution execution, final String message, final Object arg1, final Object arg2,
411             final Object arg3) throws RuntimeException
412     {
413         try
414         {
415             execution.execute();
416         }
417         catch (Throwable cause)
418         {
419             List<Object> argList = new ArrayList<>();
420             argList.add(arg1);
421             argList.add(arg2);
422             argList.add(arg3);
423             throw catchThrowable(RuntimeException.class, message, argList, cause);
424         }
425     }
426 
427     /**
428      * Tries to execute. Will throw a RuntimeException if the try fails.
429      * @param execution Execution; functional interface to execute
430      * @param message String; the message to use in the throwable, with formatting identifiers
431      * @param arg1 Object; 1st value to use for the formatting identifiers
432      * @param arg2 Object; 2nd value to use for the formatting identifiers
433      * @param arg3 Object; 3rd value to use for the formatting identifiers
434      * @param args Object...; potential 4th and further values to use for the formatting identifiers
435      * @throws RuntimeException on failed Try
436      */
437     public static void execute(final Execution execution, final String message, final Object arg1, final Object arg2,
438             final Object arg3, final Object... args) throws RuntimeException
439     {
440         try
441         {
442             execution.execute();
443         }
444         catch (Throwable cause)
445         {
446             List<Object> argList = new ArrayList<>();
447             argList.add(arg1);
448             argList.add(arg2);
449             argList.add(arg3);
450             argList.addAll(Arrays.asList(args));
451             throw catchThrowable(RuntimeException.class, message, argList, cause);
452         }
453     }
454 
455     /**
456      * Tries to execute. Will throw a specified Throwable if the try fails.
457      * @param execution Execution; functional interface to execute
458      * @param throwableClass Class&lt;T&gt;; class of the throwable to throw
459      * @param message String; the message to use in the throwable
460      * @param <T> throwable type
461      * @throws T throwable on failed Try
462      */
463     public static <T extends Throwable> void execute(final Execution execution, final Class<T> throwableClass,
464             final String message) throws T
465     {
466         try
467         {
468             execution.execute();
469         }
470         catch (Throwable cause)
471         {
472             throw catchThrowable(throwableClass, message, new ArrayList<>(), cause);
473         }
474     }
475 
476     /**
477      * Tries to execute. Will throw a specified Throwable if the try fails.
478      * @param execution Execution; functional interface to execute
479      * @param throwableClass Class&lt;T&gt;; class of the throwable to throw
480      * @param message String; the message to use in the throwable, with formatting identifier
481      * @param arg Object; value to use for the formatting identifier
482      * @param <T> throwable type
483      * @throws T throwable on failed Try
484      */
485     public static <T extends Throwable> void execute(final Execution execution, final Class<T> throwableClass,
486             final String message, final Object arg) throws T
487     {
488         try
489         {
490             execution.execute();
491         }
492         catch (Throwable cause)
493         {
494             List<Object> argList = new ArrayList<>();
495             argList.add(arg);
496             throw catchThrowable(throwableClass, message, argList, cause);
497         }
498     }
499 
500     /**
501      * Tries to execute. Will throw a specified Throwable if the try fails.
502      * @param execution Execution; functional interface to execute
503      * @param throwableClass Class&lt;T&gt;; class of the throwable to throw
504      * @param message String; the message to use in the throwable, with formatting identifiers
505      * @param arg1 Object; 1st value to use for the formatting identifiers
506      * @param arg2 Object; 2nd value to use for the formatting identifiers
507      * @param <T> throwable type
508      * @throws T throwable on failed Try
509      */
510     public static <T extends Throwable> void execute(final Execution execution, final Class<T> throwableClass,
511             final String message, final Object arg1, final Object arg2) throws T
512     {
513         try
514         {
515             execution.execute();
516         }
517         catch (Throwable cause)
518         {
519             List<Object> argList = new ArrayList<>();
520             argList.add(arg1);
521             argList.add(arg2);
522             throw catchThrowable(throwableClass, message, argList, cause);
523         }
524     }
525 
526     /**
527      * Tries to execute. Will throw a specified Throwable if the try fails.
528      * @param execution Execution; functional interface to execute
529      * @param throwableClass Class&lt;T&gt;; class of the throwable to throw
530      * @param message String; the message to use in the throwable, with formatting identifiers
531      * @param arg1 Object; 1st value to use for the formatting identifiers
532      * @param arg2 Object; 2nd value to use for the formatting identifiers
533      * @param arg3 Object; 3rd value to use for the formatting identifiers
534      * @param <T> throwable type
535      * @throws T throwable on failed Try
536      */
537     public static <T extends Throwable> void execute(final Execution execution, final Class<T> throwableClass,
538             final String message, final Object arg1, final Object arg2, final Object arg3) throws T
539     {
540         try
541         {
542             execution.execute();
543         }
544         catch (Throwable cause)
545         {
546             List<Object> argList = new ArrayList<>();
547             argList.add(arg1);
548             argList.add(arg2);
549             argList.add(arg3);
550             throw catchThrowable(throwableClass, message, argList, cause);
551         }
552     }
553 
554     /**
555      * Tries to execute. Will throw a specified Throwable if the try fails.
556      * @param execution Execution; functional interface to execute
557      * @param throwableClass Class&lt;T&gt;; class of the throwable to throw
558      * @param message String; the message to use in the throwable, with formatting identifiers
559      * @param arg1 Object; 1st value to use for the formatting identifiers
560      * @param arg2 Object; 2nd value to use for the formatting identifiers
561      * @param arg3 Object; 3rd value to use for the formatting identifiers
562      * @param args Object...; potential 4th and further values to use for the formatting identifiers
563      * @param <T> throwable type
564      * @throws T throwable on failed Try
565      */
566     public static <T extends Throwable> void execute(final Execution execution, final Class<T> throwableClass,
567             final String message, final Object arg1, final Object arg2, final Object arg3, final Object... args) throws T
568     {
569         try
570         {
571             execution.execute();
572         }
573         catch (Throwable cause)
574         {
575             List<Object> argList = new ArrayList<>();
576             argList.add(arg1);
577             argList.add(arg2);
578             argList.add(arg3);
579             argList.addAll(Arrays.asList(args));
580             throw catchThrowable(throwableClass, message, argList, cause);
581         }
582     }
583 
584     // Core of assign/execute methods
585 
586     /**
587      * Core method to create the Throwable to throw.
588      * @param throwableClass Class&lt;T&gt;; the throwable class
589      * @param message String; the message to construct when an exception is thrown.
590      * @param argList List&lt;Object&gt;; List&lt;Object&gt; the arguments as implied by format escapes in
591      *            &lt;code&gt;message&lt;/code&gt;
592      * @param cause Throwable; underlying cause thrown inside the assign()/execute()
593      * @param <T> throwable type
594      * @return T; throwable
595      */
596     private static <T extends Throwable> T catchThrowable(final Class<T> throwableClass, final String message,
597             final List<Object> argList, final Throwable cause)
598     {
599         // create a clear message
600         List<StackTraceElement> steList = new ArrayList<>(Arrays.asList(new Throwable().getStackTrace()));
601         // see https://stackoverflow.com/questions/2411487/nullpointerexception-in-java-with-no-stacktrace
602         // and https://hg.openjdk.java.net/jdk/jdk/file/tip/src/hotspot/share/opto/graphKit.cpp
603         if (steList.size() > 2)
604         {
605             steList.remove(0); // remove the catchThrowable(...) call
606             steList.remove(0); // remove the Try.assign/execute(...) call
607         }
608         StackTraceElement[] ste = steList.toArray(new StackTraceElement[steList.size()]);
609         String where = ste[0].getClassName() + "." + ste[0].getMethodName() + " (" + ste[0].getLineNumber() + "): ";
610         Object[] args = argList.toArray();
611         String formattedMessage;
612         try
613         {
614             formattedMessage = where + String.format(message, args);
615         }
616         catch (IllegalFormatException exception)
617         {
618             formattedMessage = where + message + " [FormatException; args=" + argList + "]";
619         }
620 
621         // throw all other exceptions through reflection
622         T exception;
623         try
624         {
625             Constructor<T> constructor =
626                     ClassUtil.resolveConstructor(throwableClass, new Class<?>[] {String.class, Throwable.class});
627             List<StackTraceElement> steCause = new ArrayList<>(Arrays.asList(cause.getStackTrace()));
628             // see https://stackoverflow.com/questions/2411487/nullpointerexception-in-java-with-no-stacktrace
629             // and https://hg.openjdk.java.net/jdk/jdk/file/tip/src/hotspot/share/opto/graphKit.cpp
630             if (steCause.size() > 3)
631             {
632                 steCause.remove(steCause.size() - 1); // remove method that called Try.assign/execute(...)
633                 steCause.remove(steCause.size() - 1); // remove the Try.assign/execute(...) call
634                 steCause.remove(steCause.size() - 1); // remove the Assignment/Execution implementation (can be lambda$#)
635                 cause.setStackTrace(steCause.toArray(new StackTraceElement[steCause.size()]));
636             }
637             exception = constructor.newInstance(formattedMessage, cause);
638             exception.setStackTrace(ste);
639         }
640         catch (Throwable t)
641         {
642             RuntimeException rte = new RuntimeException(t.getMessage(), new Exception(formattedMessage, cause));
643             rte.setStackTrace(ste);
644             throw rte;
645         }
646         return exception;
647     }
648 
649     // Test fail/succeed (JUNIT)
650 
651     /**
652      * Fails if the assignment succeeds.
653      * @param assignment Assignment&lt;V&gt;; functional interface to assign value
654      * @param <V> value type
655      * @return V; value to assign
656      */
657     public static <V> V testFail(final Assignment<V> assignment)
658     {
659         return testFail(assignment, null, Throwable.class);
660     }
661 
662     /**
663      * Fails if the assignment succeeds.
664      * @param assignment Assignment&lt;V&gt;; functional interface to assign value
665      * @param message String; fail message
666      * @param <V> value type
667      * @return V; value to assign
668      */
669     public static <V> V testFail(final Assignment<V> assignment, final String message)
670     {
671         return testFail(assignment, message, Throwable.class);
672     }
673 
674     /**
675      * Fails if the assignment succeeds.
676      * @param assignment Assignment&lt;V&gt;; functional interface to assign value
677      * @param throwableClass Class&lt;T&gt;; throwable class to catch
678      * @param <V> value type
679      * @param <T> throwable type
680      * @return V; value to assign
681      */
682     public static <V, T extends Throwable> V testFail(final Assignment<V> assignment, final Class<T> throwableClass)
683     {
684         return testFail(assignment, null, throwableClass);
685     }
686 
687     /**
688      * Fails if the assignment succeeds.
689      * @param assignment Assignment&lt;V&gt;; functional interface to assign value
690      * @param message String; fail message
691      * @param throwableClass Class&lt;T&gt;; throwable class to catch
692      * @param <V> value type
693      * @param <T> throwable type
694      * @return V; value to assign
695      */
696     public static <V, T extends Throwable> V testFail(final Assignment<V> assignment, final String message,
697             final Class<T> throwableClass)
698     {
699         V value;
700         try
701         {
702             value = assignment.assign();
703             throw new AssertionError(message);
704         }
705         catch (Throwable cause)
706         {
707             if (!throwableClass.isAssignableFrom(cause.getClass()))
708             {
709                 throw new AssertionError("Assignment failed on unexpected Throwable, expected ("
710                         + throwableClass.getSimpleName() + "), but got (" + cause.getClass().getSimpleName() + ").");
711             }
712             // expected to fail
713             value = null;
714         }
715         return value;
716     }
717 
718     /**
719      * Fails if the assignment does not succeed.
720      * @param assignment Assignment&lt;V&gt;; functional interface to assign value
721      * @param <V> value type
722      * @return V; value to assign
723      */
724     public static <V> V testSucceed(final Assignment<V> assignment)
725     {
726         return testSucceed(assignment, null, Throwable.class);
727     }
728 
729     /**
730      * Fails if the assignment does not succeed.
731      * @param assignment Assignment&lt;V&gt;; functional interface to assign value
732      * @param message String; fail message
733      * @param <V> value type
734      * @return V; value to assign
735      */
736     public static <V> V testSucceed(final Assignment<V> assignment, final String message)
737     {
738         return testSucceed(assignment, message, Throwable.class);
739     }
740 
741     /**
742      * Fails if the assignment does not succeed.
743      * @param assignment Assignment&lt;V&gt;; functional interface to assign value
744      * @param throwableClass Class&lt;T&gt;; throwable class to catch
745      * @param <V> value type
746      * @param <T> throwable type
747      * @return V; value to assign
748      */
749     public static <V, T extends Throwable> V testSucceed(final Assignment<V> assignment, final Class<T> throwableClass)
750     {
751         return testSucceed(assignment, null, throwableClass);
752     }
753 
754     /**
755      * Fails if the assignment does not succeed.
756      * @param assignment Assignment&lt;V&gt;; functional interface to assign value
757      * @param message String; fail message
758      * @param throwableClass Class&lt;T&gt;; throwable class to catch
759      * @param <V> value type
760      * @param <T> throwable type
761      * @return V; value to assign
762      */
763     public static <V, T extends Throwable> V testSucceed(final Assignment<V> assignment, final String message,
764             final Class<T> throwableClass)
765     {
766         V value;
767         try
768         {
769             value = assignment.assign();
770         }
771         catch (Throwable cause)
772         {
773             if (throwableClass.isAssignableFrom(cause.getClass()))
774             {
775                 value = null;
776             }
777             else
778             {
779                 throw new AssertionError("Assignment failed on unexpected Throwable, expected ("
780                         + throwableClass.getSimpleName() + "), but got (" + cause.getClass().getSimpleName() + ").");
781             }
782         }
783         return value;
784     }
785 
786     /**
787      * Fails if the execution succeeds.
788      * @param execution Execution; functional interface to execute
789      */
790     public static void testFail(final Execution execution)
791     {
792         testFail(execution, null, Throwable.class);
793     }
794 
795     /**
796      * Fails if the execution succeeds.
797      * @param execution Execution; functional interface to execute
798      * @param message String; fail message
799      */
800     public static void testFail(final Execution execution, final String message)
801     {
802         testFail(execution, message, Throwable.class);
803     }
804 
805     /**
806      * Fails if the execution succeeds.
807      * @param execution Execution; functional interface to execute
808      * @param throwableClass Class&lt;T&gt;; throwable class to catch
809      * @param <T> throwable type
810      */
811     public static <T extends Throwable> void testFail(final Execution execution, final Class<T> throwableClass)
812     {
813         testFail(execution, null, throwableClass);
814     }
815 
816     /**
817      * Fails if the execution succeeds.
818      * @param execution Execution; functional interface to execute
819      * @param message String; fail message
820      * @param throwableClass Class&lt;T&gt;; throwable class to catch
821      * @param <T> throwable type
822      */
823     public static <T extends Throwable> void testFail(final Execution execution, final String message,
824             final Class<T> throwableClass)
825     {
826         try
827         {
828             execution.execute();
829         }
830         catch (Throwable cause)
831         {
832             if (!throwableClass.isAssignableFrom(cause.getClass()))
833             {
834                 throw new AssertionError("Execution failed on unexpected Throwable, expected (" + throwableClass.getSimpleName()
835                         + "), but got (" + cause.getClass().getSimpleName() + ").");
836             }
837             // expected to fail
838             return;
839         }
840         throw new AssertionError(message);
841     }
842 
843     /**
844      * Fails if the execution does not succeed.
845      * @param execution Execution; functional interface to execute
846      */
847     public static void testSucceed(final Execution execution)
848     {
849         testSucceed(execution, null, Throwable.class);
850     }
851 
852     /**
853      * Fails if the execution does not succeed.
854      * @param execution Execution; functional interface to execute
855      * @param message String; fail message
856      */
857     public static void testSucceed(final Execution execution, final String message)
858     {
859         testSucceed(execution, message, Throwable.class);
860     }
861 
862     /**
863      * Fails if the execution does not succeed.
864      * @param execution Execution; functional interface to execute
865      * @param throwableClass Class&lt;T&gt;; throwable class to catch
866      * @param <T> throwable type
867      */
868     public static <T extends Throwable> void testSucceed(final Execution execution, final Class<T> throwableClass)
869     {
870         testSucceed(execution, null, throwableClass);
871     }
872 
873     /**
874      * Fails if the execution does not succeed.
875      * @param execution Execution; functional interface to execute
876      * @param message String; fail message
877      * @param throwableClass Class&lt;T&gt;; throwable class to catch
878      * @param <T> throwable type
879      */
880     public static <T extends Throwable> void testSucceed(final Execution execution, final String message,
881             final Class<T> throwableClass)
882     {
883         try
884         {
885             execution.execute();
886         }
887         catch (Throwable cause)
888         {
889             if (throwableClass.isAssignableFrom(cause.getClass()))
890             {
891                 throw new AssertionError(message);
892             }
893             else
894             {
895                 throw new AssertionError("Execution failed on unexpected Throwable, expected (" + throwableClass.getSimpleName()
896                         + "), but got (" + cause.getClass().getSimpleName() + ").");
897             }
898         }
899     }
900 
901     // Interfaces
902 
903     /**
904      * Functional interface for calls to Try.assign(...). For this a lambda expression can be used.
905      * 
906      * <pre>
907      * FileInputStream fis = Try.assign(() -&gt; new FileInputStream(fileString), IllegalArgumentException.class,
908      *         "File %s is not a valid file.", fileString);
909      * </pre>
910      * <p>
911      * Copyright (c) 2013-2021 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved.
912      * <br>
913      * BSD-style license. See <a href="https://djutils.org/docs/current/djutils/licenses.html">DJUTILS License</a>.
914      * <p>
915      * @version $Revision$, $LastChangedDate$, by $Author$, initial version 31 jan. 2018 <br>
916      * @author <a href="https://www.tudelft.nl/averbraeck">Alexander Verbraeck</a>
917      * @author <a href="https://www.tudelft.nl/staff/p.knoppers/">Peter Knoppers</a>
918      * @param <V> value type
919      */
920     @FunctionalInterface
921     public interface Assignment<V>
922     {
923         /**
924          * Returns a value which is obtained from the context in which the Assignment was created.
925          * @return value which is obtained from the context in which the Assignment was created
926          * @throws Throwable on any throwable in the try
927          */
928         V assign() throws Throwable;
929     }
930 
931     /**
932      * Functional interface for calls to Try.execute(...). For this a lambda expression can be used.
933      * 
934      * <pre>
935      * Try.execute(() -&gt; fis.close(), "Could not close the file.");
936      * </pre>
937      * <p>
938      * Copyright (c) 2013-2021 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved.
939      * <br>
940      * BSD-style license. See <a href="https://djutils.org/docs/current/djutils/licenses.html">DJUTILS License</a>.
941      * <p>
942      * @version $Revision$, $LastChangedDate$, by $Author$, initial version 31 jan. 2018 <br>
943      * @author <a href="https://www.tudelft.nl/averbraeck">Alexander Verbraeck</a>
944      * @author <a href="https://www.tudelft.nl/staff/p.knoppers/">Peter Knoppers</a>
945      */
946     @FunctionalInterface
947     public interface Execution
948     {
949         /**
950          * Executes some code using the context in which the Execution was created.
951          * @throws Throwable on any throwable in the try
952          */
953         void execute() throws Throwable;
954     }
955 
956 }