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         try
700         {
701             assignment.assign();
702         }
703         catch (Throwable cause)
704         {
705             if (!throwableClass.isAssignableFrom(cause.getClass()))
706             {
707                 throw new AssertionError("Assignment failed on unexpected Throwable, expected ("
708                         + throwableClass.getSimpleName() + "), but got (" + cause.getClass().getSimpleName() + ").");
709             }
710             return null;
711         }
712         throw new AssertionError(message);
713     }
714 
715     /**
716      * Fails if the assignment does not succeed.
717      * @param assignment Assignment&lt;V&gt;; functional interface to assign value
718      * @param <V> value type
719      * @return V; value to assign
720      */
721     public static <V> V testSucceed(final Assignment<V> assignment)
722     {
723         return testSucceed(assignment, null, Throwable.class);
724     }
725 
726     /**
727      * Fails if the assignment does not succeed.
728      * @param assignment Assignment&lt;V&gt;; functional interface to assign value
729      * @param message String; fail message
730      * @param <V> value type
731      * @return V; value to assign
732      */
733     public static <V> V testSucceed(final Assignment<V> assignment, final String message)
734     {
735         return testSucceed(assignment, message, Throwable.class);
736     }
737 
738     /**
739      * Fails if the assignment does not succeed.
740      * @param assignment Assignment&lt;V&gt;; functional interface to assign value
741      * @param throwableClass Class&lt;T&gt;; throwable class to catch
742      * @param <V> value type
743      * @param <T> throwable type
744      * @return V; value to assign
745      */
746     public static <V, T extends Throwable> V testSucceed(final Assignment<V> assignment, final Class<T> throwableClass)
747     {
748         return testSucceed(assignment, null, throwableClass);
749     }
750 
751     /**
752      * Fails if the assignment does not succeed.
753      * @param assignment Assignment&lt;V&gt;; functional interface to assign value
754      * @param message String; fail message
755      * @param throwableClass Class&lt;T&gt;; throwable class to catch
756      * @param <V> value type
757      * @param <T> throwable type
758      * @return V; value to assign
759      */
760     public static <V, T extends Throwable> V testSucceed(final Assignment<V> assignment, final String message,
761             final Class<T> throwableClass)
762     {
763         V value;
764         try
765         {
766             value = assignment.assign();
767         }
768         catch (Throwable cause)
769         {
770             if (throwableClass.isAssignableFrom(cause.getClass()))
771             {
772                 value = null;
773             }
774             else
775             {
776                 throw new AssertionError("Assignment failed on unexpected Throwable, expected ("
777                         + throwableClass.getSimpleName() + "), but got (" + cause.getClass().getSimpleName() + ").");
778             }
779         }
780         return value;
781     }
782 
783     /**
784      * Fails if the execution succeeds.
785      * @param execution Execution; functional interface to execute
786      */
787     public static void testFail(final Execution execution)
788     {
789         testFail(execution, null, Throwable.class);
790     }
791 
792     /**
793      * Fails if the execution succeeds.
794      * @param execution Execution; functional interface to execute
795      * @param message String; fail message
796      */
797     public static void testFail(final Execution execution, final String message)
798     {
799         testFail(execution, message, Throwable.class);
800     }
801 
802     /**
803      * Fails if the execution succeeds.
804      * @param execution Execution; functional interface to execute
805      * @param throwableClass Class&lt;T&gt;; throwable class to catch
806      * @param <T> throwable type
807      */
808     public static <T extends Throwable> void testFail(final Execution execution, final Class<T> throwableClass)
809     {
810         testFail(execution, null, throwableClass);
811     }
812 
813     /**
814      * Fails if the execution succeeds.
815      * @param execution Execution; functional interface to execute
816      * @param message String; fail message
817      * @param throwableClass Class&lt;T&gt;; throwable class to catch
818      * @param <T> throwable type
819      */
820     public static <T extends Throwable> void testFail(final Execution execution, final String message,
821             final Class<T> throwableClass)
822     {
823         try
824         {
825             execution.execute();
826         }
827         catch (Throwable cause)
828         {
829             if (!throwableClass.isAssignableFrom(cause.getClass()))
830             {
831                 throw new AssertionError("Execution failed on unexpected Throwable, expected (" + throwableClass.getSimpleName()
832                         + "), but got (" + cause.getClass().getSimpleName() + ").");
833             }
834             // expected to fail
835             return;
836         }
837         throw new AssertionError(message);
838     }
839 
840     /**
841      * Fails if the execution does not succeed.
842      * @param execution Execution; functional interface to execute
843      */
844     public static void testSucceed(final Execution execution)
845     {
846         testSucceed(execution, null, Throwable.class);
847     }
848 
849     /**
850      * Fails if the execution does not succeed.
851      * @param execution Execution; functional interface to execute
852      * @param message String; fail message
853      */
854     public static void testSucceed(final Execution execution, final String message)
855     {
856         testSucceed(execution, message, Throwable.class);
857     }
858 
859     /**
860      * Fails if the execution does not succeed.
861      * @param execution Execution; functional interface to execute
862      * @param throwableClass Class&lt;T&gt;; throwable class to catch
863      * @param <T> throwable type
864      */
865     public static <T extends Throwable> void testSucceed(final Execution execution, final Class<T> throwableClass)
866     {
867         testSucceed(execution, null, throwableClass);
868     }
869 
870     /**
871      * Fails if the execution does not succeed.
872      * @param execution Execution; functional interface to execute
873      * @param message String; fail message
874      * @param throwableClass Class&lt;T&gt;; throwable class to catch
875      * @param <T> throwable type
876      */
877     public static <T extends Throwable> void testSucceed(final Execution execution, final String message,
878             final Class<T> throwableClass)
879     {
880         try
881         {
882             execution.execute();
883         }
884         catch (Throwable cause)
885         {
886             if (throwableClass.isAssignableFrom(cause.getClass()))
887             {
888                 throw new AssertionError(message);
889             }
890             else
891             {
892                 throw new AssertionError("Execution failed on unexpected Throwable, expected (" + throwableClass.getSimpleName()
893                         + "), but got (" + cause.getClass().getSimpleName() + ").");
894             }
895         }
896     }
897 
898     // Interfaces
899 
900     /**
901      * Functional interface for calls to Try.assign(...). For this a lambda expression can be used.
902      * 
903      * <pre>
904      * FileInputStream fis = Try.assign(() -&gt; new FileInputStream(fileString), IllegalArgumentException.class,
905      *         "File %s is not a valid file.", fileString);
906      * </pre>
907      * <p>
908      * Copyright (c) 2013-2021 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved.
909      * <br>
910      * BSD-style license. See <a href="https://djutils.org/docs/current/djutils/licenses.html">DJUTILS License</a>.
911      * <p>
912      * @version $Revision$, $LastChangedDate$, by $Author$, initial version 31 jan. 2018 <br>
913      * @author <a href="https://www.tudelft.nl/averbraeck">Alexander Verbraeck</a>
914      * @author <a href="https://www.tudelft.nl/staff/p.knoppers/">Peter Knoppers</a>
915      * @param <V> value type
916      */
917     @FunctionalInterface
918     public interface Assignment<V>
919     {
920         /**
921          * Returns a value which is obtained from the context in which the Assignment was created.
922          * @return value which is obtained from the context in which the Assignment was created
923          * @throws Throwable on any throwable in the try
924          */
925         V assign() throws Throwable;
926     }
927 
928     /**
929      * Functional interface for calls to Try.execute(...). For this a lambda expression can be used.
930      * 
931      * <pre>
932      * Try.execute(() -&gt; fis.close(), "Could not close the file.");
933      * </pre>
934      * <p>
935      * Copyright (c) 2013-2021 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved.
936      * <br>
937      * BSD-style license. See <a href="https://djutils.org/docs/current/djutils/licenses.html">DJUTILS License</a>.
938      * <p>
939      * @version $Revision$, $LastChangedDate$, by $Author$, initial version 31 jan. 2018 <br>
940      * @author <a href="https://www.tudelft.nl/averbraeck">Alexander Verbraeck</a>
941      * @author <a href="https://www.tudelft.nl/staff/p.knoppers/">Peter Knoppers</a>
942      */
943     @FunctionalInterface
944     public interface Execution
945     {
946         /**
947          * Executes some code using the context in which the Execution was created.
948          * @throws Throwable on any throwable in the try
949          */
950         void execute() throws Throwable;
951     }
952 
953 }