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.ToDoubleFunction;
028
029/**
030 * Represents a function that produces a double-valued result, may throw
031 * exception. This is the {@code double}-producing primitive specialization for
032 * {@link FunctionWithException}.
033 * <h3>General contract</h3>
034 * <ul>
035 * <li><b>{@link #applyAsDouble(Object) double applyAsDouble(T value) throws
036 * E}</b>&nbsp;-&nbsp;The functional method.</li>
037 * <li><b>uncheck</b>&nbsp;-&nbsp;Return a {@code ToDoubleFunction<T>}</li>
038 * <li><b>lift</b>&nbsp;-&nbsp;Return a {@code ToDoubleFunction<T>}</li>
039 * <li><b>ignore</b>&nbsp;-&nbsp;Return a {@code ToDoubleFunction<T>}</li>
040 * </ul>
041 *
042 * @see ToDoubleFunction
043 * @param <T>
044 *            the type of the input to the function
045 * @param <E>
046 *            the type of the potential exception of the function
047 */
048@FunctionalInterface
049public interface ToDoubleFunctionWithException<T, E extends Exception>
050                extends PrimitiveReturnExceptionHandlerSupport<ToDoubleFunction<T>, ToDoubleFunctionWithException<T, E>>,
051                DoubleDefaultValue {
052
053        /**
054         * Applies this function to the given argument.
055         *
056         * @param value
057         *            the function argument
058         * @return the function result
059         * @throws E
060         *             any exception
061         * @see ToDoubleFunction#applyAsDouble(Object)
062         */
063        double applyAsDouble(T value) throws E;
064
065        @Override
066        default ToDoubleFunction<T> uncheckOrIgnore(boolean uncheck) {
067                return value -> {
068                        try {
069                                return applyAsDouble(value);
070                        } catch (Exception e) {
071                                PrimitiveReturnExceptionHandlerSupport.handleException(uncheck, e, exceptionMapper());
072                                return defaultValue();
073                        }
074                };
075        }
076
077        /**
078         * Returns a function that always throw exception.
079         *
080         * @param exceptionBuilder
081         *            the supplier to create the exception
082         * @param <T>
083         *            the type of the input to the function
084         * @param <E>
085         *            the type of the exception
086         * @return a function that always throw exception
087         */
088        static <T, E extends Exception> ToDoubleFunctionWithException<T, E> failing(Supplier<E> exceptionBuilder) {
089                return t -> {
090                        throw exceptionBuilder.get();
091                };
092        }
093
094        /**
095         * Converts a {@code ToDoubleFunctionException} to a {@code ToDoubleFunction}
096         * that convert exception to {@code RuntimeException}.
097         *
098         * @param function
099         *            to be unchecked
100         * @param <T>
101         *            the type of the input to the function
102         * @param <E>
103         *            the type of the potential exception
104         * @return the unchecked exception
105         * @see #uncheck()
106         * @see #unchecked(ToDoubleFunctionWithException, Function)
107         * @throws NullPointerException
108         *             if function is null
109         */
110        static <T, E extends Exception> ToDoubleFunction<T> unchecked(ToDoubleFunctionWithException<T, E> function) {
111                return verifyFunction(function).uncheck();
112        }
113
114        /**
115         * Converts a {@code ToDoubleFunctionWithException} to a
116         * {@code ToDoubleFunction} that convert exception to {@code RuntimeException}
117         * by using the provided mapping function.
118         *
119         * @param function
120         *            the be unchecked
121         * @param exceptionMapper
122         *            a function to convert the exception to the runtime exception.
123         * @param <T>
124         *            the type of the input to the function
125         * @param <E>
126         *            the type of the potential exception
127         * @return the unchecked function
128         * @see #uncheck()
129         * @see #unchecked(ToDoubleFunctionWithException)
130         * @throws NullPointerException
131         *             if function or exceptionMapper is null
132         */
133        static <T, E extends Exception> ToDoubleFunction<T> unchecked(ToDoubleFunctionWithException<T, E> function,
134                        Function<Exception, RuntimeException> exceptionMapper) {
135                verifyFunction(function);
136                verifyExceptionMapper(exceptionMapper);
137                return new ToDoubleFunctionWithException<T, E>() {
138
139                        @Override
140                        public double applyAsDouble(T value) throws E {
141                                return function.applyAsDouble(value);
142                        }
143
144                        @Override
145                        public Function<Exception, RuntimeException> exceptionMapper() {
146                                return exceptionMapper;
147                        }
148
149                }.uncheck();
150        }
151
152        /**
153         * Converts a {@code ToDoubleFunctionWithException} to a lifted
154         * {@code ToDoubleFunction} returning {@code 0} in case of exception.
155         *
156         * @param function
157         *            to be lifted
158         * @param <T>
159         *            the type of the input to the function
160         * @param <E>
161         *            the type of the potential exception
162         * @return the lifted function
163         * @see #lift()
164         * @throws NullPointerException
165         *             if function is null
166         */
167        static <T, E extends Exception> ToDoubleFunction<T> lifted(ToDoubleFunctionWithException<T, E> function) {
168                return verifyFunction(function).lift();
169        }
170
171        /**
172         * Converts a {@code ToDoubleFunctionWithException} to a lifted
173         * {@code ToDoubleFunction} returning {@code 0} in case of exception.
174         *
175         * @param function
176         *            to be lifted
177         * @param <T>
178         *            the type of the input to the function
179         * @param <E>
180         *            the type of the potential exception
181         * @return the lifted function
182         * @see #ignore()
183         * @throws NullPointerException
184         *             if function is null
185         */
186        static <T, E extends Exception> ToDoubleFunction<T> ignored(ToDoubleFunctionWithException<T, E> function) {
187                return verifyFunction(function).ignore();
188        }
189
190        /**
191         * Converts a {@code ToDoubleFunctionWithException} to a lifted
192         * {@code ToDoubleFunction} returning a default value in case of exception.
193         *
194         * @param function
195         *            to be lifted
196         * @param defaultValue
197         *            the value in case of exception
198         * @param <T>
199         *            the type of the input to the function
200         * @param <E>
201         *            the type of the potential exception
202         * @return the lifted function
203         * @see #ignore()
204         * @see #ignored(ToDoubleFunctionWithException)
205         * @throws NullPointerException
206         *             if function is null
207         * @since 3.0.0
208         */
209        static <T, E extends Exception> ToDoubleFunction<T> ignored(ToDoubleFunctionWithException<T, E> function,
210                        double defaultValue) {
211                verifyFunction(function);
212                return new ToDoubleFunctionWithException<T, E>() {
213
214                        @Override
215                        public double applyAsDouble(T value) throws E {
216                                return function.applyAsDouble(value);
217                        }
218
219                        @Override
220                        public double defaultValue() {
221                                return defaultValue;
222                        }
223
224                }.ignore();
225        }
226
227}