001/**
002 * Powerunit - A JDK1.8 test framework
003 * Copyright (C) 2014 Mathieu Boretti.
004 *
005 * This file is part of Powerunit
006 *
007 * Powerunit is free software: you can redistribute it and/or modify
008 * it under the terms of the GNU General Public License as published by
009 * the Free Software Foundation, either version 3 of the License, or
010 * (at your option) any later version.
011 *
012 * Powerunit is distributed in the hope that it will be useful,
013 * but WITHOUT ANY WARRANTY; without even the implied warranty of
014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
015 * GNU General Public License for more details.
016 *
017 * You should have received a copy of the GNU General Public License
018 * along with Powerunit. If not, see <http://www.gnu.org/licenses/>.
019 */
020package ch.powerunit.extensions.exceptions;
021
022import static ch.powerunit.extensions.exceptions.Constants.verifyExceptionMapper;
023import static ch.powerunit.extensions.exceptions.Constants.verifyFunction;
024
025import java.util.function.Function;
026import java.util.function.Supplier;
027import java.util.function.ToDoubleBiFunction;
028
029/**
030 * Represents a function that accepts two arguments, may thrown exception and
031 * produces a double-valued result. This is the {@code double}-producing
032 * primitive specialization for {@link BiFunctionWithException}.
033 * <h3>General contract</h3>
034 * <ul>
035 * <li><b>{@link #applyAsDouble(Object, Object) double applyAsDouble(T t, U u)
036 * throws E}</b>&nbsp;-&nbsp;The functional method.</li>
037 * <li><b>uncheck</b>&nbsp;-&nbsp;Return a {@code ToDoubleBiFunction<T, U>}</li>
038 * <li><b>lift</b>&nbsp;-&nbsp;Return a {@code ToDoubleBiFunction<T, U>}</li>
039 * <li><b>ignore</b>&nbsp;-&nbsp;Return a {@code ToDoubleBiFunction<T, U>}</li>
040 * </ul>
041 *
042 * @see ToDoubleBiFunction
043 * @param <T>
044 *            the type of the first argument to the function
045 * @param <U>
046 *            the type of the second argument the function
047 * @param <E>
048 *            the type of the potential exception of the function
049 */
050@FunctionalInterface
051public interface ToDoubleBiFunctionWithException<T, U, E extends Exception> extends
052                PrimitiveReturnExceptionHandlerSupport<ToDoubleBiFunction<T, U>, ToDoubleBiFunctionWithException<T, U, E>>,
053                DoubleDefaultValue {
054
055        /**
056         * Applies this function to the given arguments.
057         *
058         * @param t
059         *            the first input argument
060         * @param u
061         *            the first second argument
062         * @return the function result
063         * @throws E
064         *             any exception
065         * @see ToDoubleBiFunction#applyAsDouble(Object, Object)
066         */
067        double applyAsDouble(T t, U u) throws E;
068
069        @Override
070        default ToDoubleBiFunction<T, U> uncheckOrIgnore(boolean uncheck) {
071                return (t, u) -> {
072                        try {
073                                return applyAsDouble(t, u);
074                        } catch (Exception e) {
075                                PrimitiveReturnExceptionHandlerSupport.handleException(uncheck, e, exceptionMapper());
076                                return defaultValue();
077                        }
078                };
079        }
080
081        /**
082         * Returns a function that always throw exception.
083         *
084         * @param exceptionBuilder
085         *            the supplier to create the exception
086         * @param <T>
087         *            the type of the first argument to the function
088         * @param <U>
089         *            the type of the second argument the function
090         * @param <E>
091         *            the type of the exception
092         * @return a function that always throw exception
093         */
094        static <T, U, E extends Exception> ToDoubleBiFunctionWithException<T, U, E> failing(Supplier<E> exceptionBuilder) {
095                return (t, u) -> {
096                        throw exceptionBuilder.get();
097                };
098        }
099
100        /**
101         * Converts a {@code ToDoubleBiFunctionWithException} to a
102         * {@code ToDoubleBiFunction} that wraps exception to {@code RuntimeException}.
103         *
104         * @param function
105         *            to be unchecked
106         * @param <T>
107         *            the type of the first argument to the function
108         * @param <U>
109         *            the type of the second argument the function
110         * @param <E>
111         *            the type of the potential exception
112         * @return the unchecked function
113         * @see #uncheck()
114         * @see #unchecked(ToDoubleBiFunctionWithException, Function)
115         * @throws NullPointerException
116         *             if function is null
117         */
118        static <T, U, E extends Exception> ToDoubleBiFunction<T, U> unchecked(
119                        ToDoubleBiFunctionWithException<T, U, E> function) {
120                return verifyFunction(function).uncheck();
121        }
122
123        /**
124         * Converts a {@code ToDoubleBiFunctionWithException} to a
125         * {@code ToDoubleBiFunction} that wraps exception to {@code RuntimeException}
126         * by using the provided mapping function.
127         *
128         * @param function
129         *            the be unchecked
130         * @param exceptionMapper
131         *            a function to convert the exception to the runtime exception.
132         * @param <T>
133         *            the type of the first argument to the function
134         * @param <U>
135         *            the type of the second argument the function
136         * @param <E>
137         *            the type of the potential exception
138         * @return the unchecked function
139         * @see #uncheck()
140         * @see #unchecked(ToDoubleBiFunctionWithException)
141         * @throws NullPointerException
142         *             if function or exception is null
143         */
144        static <T, U, E extends Exception> ToDoubleBiFunction<T, U> unchecked(
145                        ToDoubleBiFunctionWithException<T, U, E> function, Function<Exception, RuntimeException> exceptionMapper) {
146                verifyFunction(function);
147                verifyExceptionMapper(exceptionMapper);
148                return new ToDoubleBiFunctionWithException<T, U, E>() {
149
150                        @Override
151                        public double applyAsDouble(T t, U u) throws E {
152                                return function.applyAsDouble(t, u);
153                        }
154
155                        @Override
156                        public Function<Exception, RuntimeException> exceptionMapper() {
157                                return exceptionMapper;
158                        }
159
160                }.uncheck();
161        }
162
163        /**
164         * Converts a {@code ToDoubleBiFunctionWithException} to a lifted
165         * {@code ToDoubleBiFunction} returning {@code 0} in case of exception.
166         *
167         * @param function
168         *            to be lifted
169         * @param <T>
170         *            the type of the first argument to the function
171         * @param <U>
172         *            the type of the second argument the function
173         * @param <E>
174         *            the type of the potential exception
175         * @return the lifted function
176         * @see #lift()
177         * @throws NullPointerException
178         *             if function is null
179         */
180        static <T, U, E extends Exception> ToDoubleBiFunction<T, U> lifted(
181                        ToDoubleBiFunctionWithException<T, U, E> function) {
182                return verifyFunction(function).lift();
183        }
184
185        /**
186         * Converts a {@code ToDoubleBiFunctionWithException} to a lifted
187         * {@code ToDoubleBiFunction} returning {@code 0} in case of exception.
188         *
189         * @param function
190         *            to be lifted
191         * @param <T>
192         *            the type of the first argument to the function
193         * @param <U>
194         *            the type of the second argument the function
195         * @param <E>
196         *            the type of the potential exception
197         * @return the lifted function
198         * @see #ignore()
199         * @throws NullPointerException
200         *             if function is null
201         */
202        static <T, U, E extends Exception> ToDoubleBiFunction<T, U> ignored(
203                        ToDoubleBiFunctionWithException<T, U, E> function) {
204                return verifyFunction(function).ignore();
205        }
206
207        /**
208         * Converts a {@code ToDoubleBiFunctionWithException} to a lifted
209         * {@code ToDoubleBiFunction} returning a default value in case of exception.
210         *
211         * @param function
212         *            to be lifted
213         * @param defaultValue
214         *            value in case of exception
215         * @param <T>
216         *            the type of the first argument to the function
217         * @param <U>
218         *            the type of the second argument the function
219         * @param <E>
220         *            the type of the potential exception
221         * @return the lifted function
222         * @see #ignore()
223         * @see #ignored(ToDoubleBiFunctionWithException)
224         * @throws NullPointerException
225         *             if function is null
226         * @since 3.0.0
227         */
228        static <T, U, E extends Exception> ToDoubleBiFunction<T, U> ignored(
229                        ToDoubleBiFunctionWithException<T, U, E> function, double defaultValue) {
230                verifyFunction(function);
231                return new ToDoubleBiFunctionWithException<T, U, E>() {
232
233                        @Override
234                        public double applyAsDouble(T t, U u) throws E {
235                                return function.applyAsDouble(t, u);
236                        }
237
238                        @Override
239                        public double defaultValue() {
240                                return defaultValue;
241                        }
242
243                }.ignore();
244        }
245
246}