001/*
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements.  See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License.  You may obtain a copy of the License at
008 *
009 *      http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017package org.apache.commons.lang3;
018
019import java.io.IOException;
020import java.io.UncheckedIOException;
021import java.lang.reflect.UndeclaredThrowableException;
022import java.util.Collection;
023import java.util.Objects;
024import java.util.concurrent.Callable;
025import java.util.function.BiConsumer;
026import java.util.function.BiFunction;
027import java.util.function.BiPredicate;
028import java.util.function.Consumer;
029import java.util.function.Function;
030import java.util.function.Predicate;
031import java.util.function.Supplier;
032import java.util.stream.Stream;
033
034import org.apache.commons.lang3.Streams.FailableStream;
035import org.apache.commons.lang3.function.FailableBooleanSupplier;
036
037/**
038 * This class provides utility functions, and classes for working with the {@code java.util.function} package, or more
039 * generally, with Java 8 lambdas. More specifically, it attempts to address the fact that lambdas are supposed not to
040 * throw Exceptions, at least not checked Exceptions, AKA instances of {@link Exception}. This enforces the use of
041 * constructs like:
042 *
043 * <pre>
044 * {@code
045 *     Consumer<java.lang.reflect.Method> consumer = m -> {
046 *         try {
047 *             m.invoke(o, args);
048 *         } catch (Throwable t) {
049 *             throw Functions.rethrow(t);
050 *         }
051 *     };
052 * }</pre>
053 *
054 * <p>
055 * By replacing a {@link java.util.function.Consumer Consumer&lt;O&gt;} with a {@link FailableConsumer
056 * FailableConsumer&lt;O,? extends Throwable&gt;}, this can be written like follows:
057 * </p>
058 *
059 * <pre>
060 * {@code
061 *   Functions.accept((m) -> m.invoke(o,args));
062 * }</pre>
063 *
064 * <p>
065 * Obviously, the second version is much more concise and the spirit of Lambda expressions is met better than the second
066 * version.
067 * </p>
068 * @since 3.9
069 * @deprecated Use {@link org.apache.commons.lang3.function.Failable}.
070 */
071@Deprecated
072public class Functions {
073
074    /**
075     * A functional interface like {@link BiConsumer} that declares a {@code Throwable}.
076     *
077     * <p>TODO for 4.0: Move to org.apache.commons.lang3.function.</p>
078     *
079     * @param <O1> Consumed type 1.
080     * @param <O2> Consumed type 2.
081     * @param <T> Thrown exception.
082     * @deprecated Use {@link org.apache.commons.lang3.function.FailableBiConsumer}.
083     */
084    @Deprecated
085    @FunctionalInterface
086    public interface FailableBiConsumer<O1, O2, T extends Throwable> {
087
088        /**
089         * Accepts the consumer.
090         *
091         * @param object1 the first parameter for the consumable to accept
092         * @param object2 the second parameter for the consumable to accept
093         * @throws T Thrown when the consumer fails.
094         */
095        void accept(O1 object1, O2 object2) throws T;
096    }
097
098    /**
099     * A functional interface like {@link BiFunction} that declares a {@code Throwable}.
100     *
101     * <p>TODO for 4.0: Move to org.apache.commons.lang3.function.</p>
102     *
103     * @param <O1> Input type 1.
104     * @param <O2> Input type 2.
105     * @param <R> Return type.
106     * @param <T> Thrown exception.
107     * @deprecated Use {@link org.apache.commons.lang3.function.FailableBiFunction}.
108     */
109    @Deprecated
110    @FunctionalInterface
111    public interface FailableBiFunction<O1, O2, R, T extends Throwable> {
112
113        /**
114         * Applies this function.
115         *
116         * @param input1 the first input for the function
117         * @param input2 the second input for the function
118         * @return the result of the function
119         * @throws T Thrown when the function fails.
120         */
121        R apply(O1 input1, O2 input2) throws T;
122    }
123
124    /**
125     * A functional interface like {@link BiPredicate} that declares a {@code Throwable}.
126     *
127     * <p>TODO for 4.0: Move to org.apache.commons.lang3.function.</p>
128     *
129     * @param <O1> Predicate type 1.
130     * @param <O2> Predicate type 2.
131     * @param <T> Thrown exception.
132     * @deprecated Use {@link org.apache.commons.lang3.function.FailableBiPredicate}.
133     */
134    @Deprecated
135    @FunctionalInterface
136    public interface FailableBiPredicate<O1, O2, T extends Throwable> {
137
138        /**
139         * Tests the predicate.
140         *
141         * @param object1 the first object to test the predicate on
142         * @param object2 the second object to test the predicate on
143         * @return the predicate's evaluation
144         * @throws T if the predicate fails
145         */
146        boolean test(O1 object1, O2 object2) throws T;
147    }
148
149    /**
150     * A functional interface like {@link java.util.concurrent.Callable} that declares a {@code Throwable}.
151     *
152     * <p>TODO for 4.0: Move to org.apache.commons.lang3.function.</p>
153     *
154     * @param <R> Return type.
155     * @param <T> Thrown exception.
156     * @deprecated Use {@link org.apache.commons.lang3.function.FailableCallable}.
157     */
158    @Deprecated
159    @FunctionalInterface
160    public interface FailableCallable<R, T extends Throwable> {
161
162        /**
163         * Calls the callable.
164         *
165         * @return The value returned from the callable
166         * @throws T if the callable fails
167         */
168        R call() throws T;
169    }
170
171    /**
172     * A functional interface like {@link Consumer} that declares a {@code Throwable}.
173     *
174     * <p>TODO for 4.0: Move to org.apache.commons.lang3.function.</p>
175     *
176     * @param <O> Consumed type 1.
177     * @param <T> Thrown exception.
178     * @deprecated Use {@link org.apache.commons.lang3.function.FailableConsumer}.
179     */
180    @Deprecated
181    @FunctionalInterface
182    public interface FailableConsumer<O, T extends Throwable> {
183
184        /**
185         * Accepts the consumer.
186         *
187         * @param object the parameter for the consumable to accept
188         * @throws T Thrown when the consumer fails.
189         */
190        void accept(O object) throws T;
191    }
192
193    /**
194     * A functional interface like {@link Function} that declares a {@code Throwable}.
195     *
196     * <p>TODO for 4.0: Move to org.apache.commons.lang3.function.</p>
197     *
198     * @param <I> Input type 1.
199     * @param <R> Return type.
200     * @param <T> Thrown exception.
201     * @deprecated Use {@link org.apache.commons.lang3.function.FailableFunction}.
202     */
203    @Deprecated
204    @FunctionalInterface
205    public interface FailableFunction<I, R, T extends Throwable> {
206
207        /**
208         * Applies this function.
209         *
210         * @param input the input for the function
211         * @return the result of the function
212         * @throws T Thrown when the function fails.
213         */
214        R apply(I input) throws T;
215    }
216
217    /**
218     * A functional interface like {@link Predicate} that declares a {@code Throwable}.
219     *
220     * <p>TODO for 4.0: Move to org.apache.commons.lang3.function.</p>
221     *
222     * @param <I> Predicate type 1.
223     * @param <T> Thrown exception.
224     * @deprecated Use {@link org.apache.commons.lang3.function.FailablePredicate}.
225     */
226    @Deprecated
227    @FunctionalInterface
228    public interface FailablePredicate<I, T extends Throwable> {
229
230        /**
231         * Tests the predicate.
232         *
233         * @param object the object to test the predicate on
234         * @return the predicate's evaluation
235         * @throws T if the predicate fails
236         */
237        boolean test(I object) throws T;
238    }
239
240    /**
241     * A functional interface like {@link Runnable} that declares a {@code Throwable}.
242     *
243     * <p>TODO for 4.0: Move to org.apache.commons.lang3.function.</p>
244     *
245     * @param <T> Thrown exception.
246     * @deprecated Use {@link org.apache.commons.lang3.function.FailableRunnable}.
247     */
248    @Deprecated
249    @FunctionalInterface
250    public interface FailableRunnable<T extends Throwable> {
251
252        /**
253         * Runs the function.
254         *
255         * @throws T Thrown when the function fails.
256         */
257        void run() throws T;
258    }
259
260    /**
261     * A functional interface like {@link Supplier} that declares a {@code Throwable}.
262     *
263     * <p>TODO for 4.0: Move to org.apache.commons.lang3.function.</p>
264     *
265     * @param <R> Return type.
266     * @param <T> Thrown exception.
267     * @deprecated Use {@link org.apache.commons.lang3.function.FailableSupplier}.
268     */
269    @Deprecated
270    @FunctionalInterface
271    public interface FailableSupplier<R, T extends Throwable> {
272
273        /**
274         * Supplies an object
275         *
276         * @return a result
277         * @throws T if the supplier fails
278         */
279        R get() throws T;
280    }
281
282    /**
283     * Consumes a consumer and rethrows any exception as a {@link RuntimeException}.
284     *
285     * @param consumer the consumer to consume
286     * @param object1 the first object to consume by {@code consumer}
287     * @param object2 the second object to consume by {@code consumer}
288     * @param <O1> the type of the first argument the consumer accepts
289     * @param <O2> the type of the second argument the consumer accepts
290     * @param <T> the type of checked exception the consumer may throw
291     */
292    public static <O1, O2, T extends Throwable> void accept(final FailableBiConsumer<O1, O2, T> consumer,
293        final O1 object1, final O2 object2) {
294        run(() -> consumer.accept(object1, object2));
295    }
296
297    /**
298     * Consumes a consumer and rethrows any exception as a {@link RuntimeException}.
299     *
300     * @param consumer the consumer to consume
301     * @param object the object to consume by {@code consumer}
302     * @param <O> the type the consumer accepts
303     * @param <T> the type of checked exception the consumer may throw
304     */
305    public static <O, T extends Throwable> void accept(final FailableConsumer<O, T> consumer, final O object) {
306        run(() -> consumer.accept(object));
307    }
308
309    /**
310     * Applies a function and rethrows any exception as a {@link RuntimeException}.
311     *
312     * @param function the function to apply
313     * @param input1 the first input to apply {@code function} on
314     * @param input2 the second input to apply {@code function} on
315     * @param <O1> the type of the first argument the function accepts
316     * @param <O2> the type of the second argument the function accepts
317     * @param <O> the return type of the function
318     * @param <T> the type of checked exception the function may throw
319     * @return the value returned from the function
320     */
321    public static <O1, O2, O, T extends Throwable> O apply(final FailableBiFunction<O1, O2, O, T> function,
322        final O1 input1, final O2 input2) {
323        return get(() -> function.apply(input1, input2));
324    }
325
326    /**
327     * Applies a function and rethrows any exception as a {@link RuntimeException}.
328     *
329     * @param function the function to apply
330     * @param input the input to apply {@code function} on
331     * @param <I> the type of the argument the function accepts
332     * @param <O> the return type of the function
333     * @param <T> the type of checked exception the function may throw
334     * @return the value returned from the function
335     */
336    public static <I, O, T extends Throwable> O apply(final FailableFunction<I, O, T> function, final I input) {
337        return get(() -> function.apply(input));
338    }
339
340    /**
341     * Converts the given {@link FailableBiConsumer} into a standard {@link BiConsumer}.
342     *
343     * @param <O1> the type of the first argument of the consumers
344     * @param <O2> the type of the second argument of the consumers
345     * @param consumer a failable {@code BiConsumer}
346     * @return a standard {@code BiConsumer}
347     * @since 3.10
348     */
349    public static <O1, O2> BiConsumer<O1, O2> asBiConsumer(final FailableBiConsumer<O1, O2, ?> consumer) {
350        return (input1, input2) -> accept(consumer, input1, input2);
351    }
352
353    /**
354     * Converts the given {@link FailableBiFunction} into a standard {@link BiFunction}.
355     *
356     * @param <O1> the type of the first argument of the input of the functions
357     * @param <O2> the type of the second argument of the input of the functions
358     * @param <O> the type of the output of the functions
359     * @param function a {@code FailableBiFunction}
360     * @return a standard {@code BiFunction}
361     * @since 3.10
362     */
363    public static <O1, O2, O> BiFunction<O1, O2, O> asBiFunction(final FailableBiFunction<O1, O2, O, ?> function) {
364        return (input1, input2) -> apply(function, input1, input2);
365    }
366
367    /**
368     * Converts the given {@link FailableBiPredicate} into a standard {@link BiPredicate}.
369     *
370     * @param <O1> the type of the first argument used by the predicates
371     * @param <O2> the type of the second argument used by the predicates
372     * @param predicate a {@code FailableBiPredicate}
373     * @return a standard {@code BiPredicate}
374     * @since 3.10
375     */
376    public static <O1, O2> BiPredicate<O1, O2> asBiPredicate(final FailableBiPredicate<O1, O2, ?> predicate) {
377        return (input1, input2) -> test(predicate, input1, input2);
378    }
379
380    /**
381     * Converts the given {@link FailableCallable} into a standard {@link Callable}.
382     *
383     * @param <O> the type used by the callables
384     * @param callable a {@code FailableCallable}
385     * @return a standard {@code Callable}
386     * @since 3.10
387     */
388    public static <O> Callable<O> asCallable(final FailableCallable<O, ?> callable) {
389        return () -> call(callable);
390    }
391
392    /**
393     * Converts the given {@link FailableConsumer} into a standard {@link Consumer}.
394     *
395     * @param <I> the type used by the consumers
396     * @param consumer a {@code FailableConsumer}
397     * @return a standard {@code Consumer}
398     * @since 3.10
399     */
400    public static <I> Consumer<I> asConsumer(final FailableConsumer<I, ?> consumer) {
401        return input -> accept(consumer, input);
402    }
403
404    /**
405     * Converts the given {@link FailableFunction} into a standard {@link Function}.
406     *
407     * @param <I> the type of the input of the functions
408     * @param <O> the type of the output of the functions
409     * @param function a {code FailableFunction}
410     * @return a standard {@code Function}
411     * @since 3.10
412     */
413    public static <I, O> Function<I, O> asFunction(final FailableFunction<I, O, ?> function) {
414        return input -> apply(function, input);
415    }
416
417    /**
418     * Converts the given {@link FailablePredicate} into a standard {@link Predicate}.
419     *
420     * @param <I> the type used by the predicates
421     * @param predicate a {@code FailablePredicate}
422     * @return a standard {@code Predicate}
423     * @since 3.10
424     */
425    public static <I> Predicate<I> asPredicate(final FailablePredicate<I, ?> predicate) {
426        return input -> test(predicate, input);
427    }
428
429    /**
430     * Converts the given {@link FailableRunnable} into a standard {@link Runnable}.
431     *
432     * @param runnable a {@code FailableRunnable}
433     * @return a standard {@code Runnable}
434     * @since 3.10
435     */
436    public static Runnable asRunnable(final FailableRunnable<?> runnable) {
437        return () -> run(runnable);
438    }
439
440    /**
441     * Converts the given {@link FailableSupplier} into a standard {@link Supplier}.
442     *
443     * @param <O> the type supplied by the suppliers
444     * @param supplier a {@code FailableSupplier}
445     * @return a standard {@code Supplier}
446     * @since 3.10
447     */
448    public static <O> Supplier<O> asSupplier(final FailableSupplier<O, ?> supplier) {
449        return () -> get(supplier);
450    }
451
452    /**
453     * Calls a callable and rethrows any exception as a {@link RuntimeException}.
454     *
455     * @param callable the callable to call
456     * @param <O> the return type of the callable
457     * @param <T> the type of checked exception the callable may throw
458     * @return the value returned from the callable
459     */
460    public static <O, T extends Throwable> O call(final FailableCallable<O, T> callable) {
461        return get(callable::call);
462    }
463
464    /**
465     * Invokes a supplier, and returns the result.
466     *
467     * @param supplier The supplier to invoke.
468     * @param <O> The suppliers output type.
469     * @param <T> The type of checked exception, which the supplier can throw.
470     * @return The object, which has been created by the supplier
471     * @since 3.10
472     */
473    public static <O, T extends Throwable> O get(final FailableSupplier<O, T> supplier) {
474        try {
475            return supplier.get();
476        } catch (final Throwable t) {
477            throw rethrow(t);
478        }
479    }
480
481    /**
482     * Invokes a boolean supplier, and returns the result.
483     *
484     * @param supplier The boolean supplier to invoke.
485     * @param <T> The type of checked exception, which the supplier can throw.
486     * @return The boolean, which has been created by the supplier
487     */
488    private static <T extends Throwable> boolean getAsBoolean(final FailableBooleanSupplier<T> supplier) {
489        try {
490            return supplier.getAsBoolean();
491        } catch (final Throwable t) {
492            throw rethrow(t);
493        }
494    }
495
496    /**
497     * <p>
498     * Rethrows a {@link Throwable} as an unchecked exception. If the argument is already unchecked, namely a
499     * {@code RuntimeException} or {@code Error} then the argument will be rethrown without modification. If the
500     * exception is {@code IOException} then it will be wrapped into a {@code UncheckedIOException}. In every other
501     * cases the exception will be wrapped into a {@code
502     * UndeclaredThrowableException}
503     * </p>
504     *
505     * <p>
506     * Note that there is a declared return type for this method, even though it never returns. The reason for that is
507     * to support the usual pattern:
508     * </p>
509     *
510     * <pre>
511     * throw rethrow(myUncheckedException);</pre>
512     *
513     * <p>
514     * instead of just calling the method. This pattern may help the Java compiler to recognize that at that point an
515     * exception will be thrown and the code flow analysis will not demand otherwise mandatory commands that could
516     * follow the method call, like a {@code return} statement from a value returning method.
517     * </p>
518     *
519     * @param throwable The throwable to rethrow ossibly wrapped into an unchecked exception
520     * @return Never returns anything, this method never terminates normally.
521     */
522    public static RuntimeException rethrow(final Throwable throwable) {
523        Objects.requireNonNull(throwable, "throwable");
524        if (throwable instanceof RuntimeException) {
525            throw (RuntimeException) throwable;
526        } else if (throwable instanceof Error) {
527            throw (Error) throwable;
528        } else if (throwable instanceof IOException) {
529            throw new UncheckedIOException((IOException) throwable);
530        } else {
531            throw new UndeclaredThrowableException(throwable);
532        }
533    }
534
535    /**
536     * Runs a runnable and rethrows any exception as a {@link RuntimeException}.
537     *
538     * @param runnable The runnable to run
539     * @param <T> the type of checked exception the runnable may throw
540     */
541    public static <T extends Throwable> void run(final FailableRunnable<T> runnable) {
542        try {
543            runnable.run();
544        } catch (final Throwable t) {
545            throw rethrow(t);
546        }
547    }
548
549    /**
550     * Converts the given collection into a {@link FailableStream}. The {@link FailableStream} consists of the
551     * collections elements. Shortcut for
552     *
553     * <pre>
554     * Functions.stream(collection.stream());</pre>
555     *
556     * @param collection The collection, which is being converted into a {@link FailableStream}.
557     * @param <O> The collections element type. (In turn, the result streams element type.)
558     * @return The created {@link FailableStream}.
559     * @since 3.10
560     */
561    public static <O> FailableStream<O> stream(final Collection<O> collection) {
562        return new FailableStream<>(collection.stream());
563    }
564
565    /**
566     * Converts the given stream into a {@link FailableStream}. The {@link FailableStream} consists of the same
567     * elements, than the input stream. However, failable lambdas, like {@link FailablePredicate},
568     * {@link FailableFunction}, and {@link FailableConsumer} may be applied, rather than {@link Predicate},
569     * {@link Function}, {@link Consumer}, etc.
570     *
571     * @param stream The stream, which is being converted into a {@link FailableStream}.
572     * @param <O> The streams element type.
573     * @return The created {@link FailableStream}.
574     * @since 3.10
575     */
576    public static <O> FailableStream<O> stream(final Stream<O> stream) {
577        return new FailableStream<>(stream);
578    }
579
580    /**
581     * Tests a predicate and rethrows any exception as a {@link RuntimeException}.
582     *
583     * @param predicate the predicate to test
584     * @param object1 the first input to test by {@code predicate}
585     * @param object2 the second input to test by {@code predicate}
586     * @param <O1> the type of the first argument the predicate tests
587     * @param <O2> the type of the second argument the predicate tests
588     * @param <T> the type of checked exception the predicate may throw
589     * @return the boolean value returned by the predicate
590     */
591    public static <O1, O2, T extends Throwable> boolean test(final FailableBiPredicate<O1, O2, T> predicate,
592        final O1 object1, final O2 object2) {
593        return getAsBoolean(() -> predicate.test(object1, object2));
594    }
595
596    /**
597     * Tests a predicate and rethrows any exception as a {@link RuntimeException}.
598     *
599     * @param predicate the predicate to test
600     * @param object the input to test by {@code predicate}
601     * @param <O> the type of argument the predicate tests
602     * @param <T> the type of checked exception the predicate may throw
603     * @return the boolean value returned by the predicate
604     */
605    public static <O, T extends Throwable> boolean test(final FailablePredicate<O, T> predicate, final O object) {
606        return getAsBoolean(() -> predicate.test(object));
607    }
608
609    /**
610     * A simple try-with-resources implementation, that can be used, if your objects do not implement the
611     * {@link AutoCloseable} interface. The method executes the {@code action}. The method guarantees, that <em>all</em>
612     * the {@code resources} are being executed, in the given order, afterwards, and regardless of success, or failure.
613     * If either the original action, or any of the resource action fails, then the <em>first</em> failure (AKA
614     * {@link Throwable} is rethrown. Example use:
615     *
616     * <pre>
617     * {@code
618     *     final FileInputStream fis = new FileInputStream("my.file");
619     *     Functions.tryWithResources(useInputStream(fis), null, () -> fis.close());
620     * }</pre>
621     *
622     * @param action The action to execute. This object <em>will</em> always be invoked.
623     * @param errorHandler An optional error handler, which will be invoked finally, if any error occurred. The error
624     *        handler will receive the first error, AKA {@link Throwable}.
625     * @param resources The resource actions to execute. <em>All</em> resource actions will be invoked, in the given
626     *        order. A resource action is an instance of {@link FailableRunnable}, which will be executed.
627     * @see #tryWithResources(FailableRunnable, FailableRunnable...)
628     */
629    @SafeVarargs
630    public static void tryWithResources(final FailableRunnable<? extends Throwable> action,
631        final FailableConsumer<Throwable, ? extends Throwable> errorHandler,
632        final FailableRunnable<? extends Throwable>... resources) {
633        final FailableConsumer<Throwable, ? extends Throwable> actualErrorHandler;
634        if (errorHandler == null) {
635            actualErrorHandler = Functions::rethrow;
636        } else {
637            actualErrorHandler = errorHandler;
638        }
639        if (resources != null) {
640            for (final FailableRunnable<? extends Throwable> failableRunnable : resources) {
641                Objects.requireNonNull(failableRunnable, "runnable");
642            }
643        }
644        Throwable th = null;
645        try {
646            action.run();
647        } catch (final Throwable t) {
648            th = t;
649        }
650        if (resources != null) {
651            for (final FailableRunnable<?> runnable : resources) {
652                try {
653                    runnable.run();
654                } catch (final Throwable t) {
655                    if (th == null) {
656                        th = t;
657                    }
658                }
659            }
660        }
661        if (th != null) {
662            try {
663                actualErrorHandler.accept(th);
664            } catch (final Throwable t) {
665                throw rethrow(t);
666            }
667        }
668    }
669
670    /**
671     * A simple try-with-resources implementation, that can be used, if your objects do not implement the
672     * {@link AutoCloseable} interface. The method executes the {@code action}. The method guarantees, that <em>all</em>
673     * the {@code resources} are being executed, in the given order, afterwards, and regardless of success, or failure.
674     * If either the original action, or any of the resource action fails, then the <em>first</em> failure (AKA
675     * {@link Throwable} is rethrown. Example use:
676     *
677     * <pre>
678     * {@code
679     *     final FileInputStream fis = new FileInputStream("my.file");
680     *     Functions.tryWithResources(useInputStream(fis), () -> fis.close());
681     * }</pre>
682     *
683     * @param action The action to execute. This object <em>will</em> always be invoked.
684     * @param resources The resource actions to execute. <em>All</em> resource actions will be invoked, in the given
685     *        order. A resource action is an instance of {@link FailableRunnable}, which will be executed.
686     * @see #tryWithResources(FailableRunnable, FailableConsumer, FailableRunnable...)
687     */
688    @SafeVarargs
689    public static void tryWithResources(final FailableRunnable<? extends Throwable> action,
690        final FailableRunnable<? extends Throwable>... resources) {
691        tryWithResources(action, null, resources);
692    }
693}