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;
024import static java.util.Objects.requireNonNull;
025
026import java.util.function.DoubleUnaryOperator;
027import java.util.function.Function;
028import java.util.function.Supplier;
029
030/**
031 * Represents an operation on a single {@code double}-valued operand that may
032 * thrown exception and produces a {@code double}-valued result. This is the
033 * primitive type specialization of {@link UnaryOperatorWithException} for
034 * {@code double}.
035 * <h3>General contract</h3>
036 * <ul>
037 * <li><b>{@link #applyAsDouble(double) double applyAsDouble(double operand)
038 * throws E}</b>&nbsp;-&nbsp;The functional method.</li>
039 * <li><b>uncheck</b>&nbsp;-&nbsp;Return a {@code DoubleUnaryOperator}</li>
040 * <li><b>lift</b>&nbsp;-&nbsp;Return a {@code DoubleUnaryOperator}</li>
041 * <li><b>ignore</b>&nbsp;-&nbsp;Return a {@code DoubleUnaryOperator}</li>
042 * </ul>
043 *
044 * @see DoubleUnaryOperator
045 * @param <E>
046 *            the type of the potential exception of the function
047 */
048@FunctionalInterface
049public interface DoubleUnaryOperatorWithException<E extends Exception>
050                extends PrimitiveReturnExceptionHandlerSupport<DoubleUnaryOperator, DoubleUnaryOperatorWithException<E>>,
051                DoubleDefaultValue {
052
053        /**
054         * Applies this operator to the given operand.
055         *
056         * @param operand
057         *            the operand
058         * @return the operator result
059         * @throws E
060         *             any exception
061         * @see DoubleUnaryOperator#applyAsDouble(double)
062         */
063        double applyAsDouble(double operand) throws E;
064
065        @Override
066        default DoubleUnaryOperator uncheckOrIgnore(boolean uncheck) {
067                return operand -> {
068                        try {
069                                return applyAsDouble(operand);
070                        } catch (Exception e) {
071                                PrimitiveReturnExceptionHandlerSupport.handleException(uncheck, e, exceptionMapper());
072                                return defaultValue();
073                        }
074                };
075        }
076
077        /**
078         * Returns a composed operator that first applies the {@code before} operator to
079         * its input, and then applies this operator to the result. If evaluation of
080         * either operator throws an exception, it is relayed to the caller of the
081         * composed operator.
082         *
083         * @param before
084         *            the operator to apply before this operator is applied
085         * @return a composed operator that first applies the {@code before} operator
086         *         and then applies this operator
087         * @throws NullPointerException
088         *             if before is null
089         *
090         * @see #andThen(DoubleUnaryOperatorWithException)
091         */
092        default DoubleUnaryOperatorWithException<E> compose(DoubleUnaryOperatorWithException<? extends E> before) {
093                requireNonNull(before);
094                return v -> applyAsDouble(before.applyAsDouble(v));
095        }
096
097        /**
098         * Returns a composed operator that first applies this operator to its input,
099         * and then applies the {@code after} operator to the result. If evaluation of
100         * either operator throws an exception, it is relayed to the caller of the
101         * composed operator.
102         *
103         * @param after
104         *            the operator to apply after this operator is applied
105         * @return a composed operator that first applies this operator and then applies
106         *         the {@code after} operator
107         * @throws NullPointerException
108         *             if after is null
109         *
110         * @see #compose(DoubleUnaryOperatorWithException)
111         */
112        default DoubleUnaryOperatorWithException<E> andThen(DoubleUnaryOperatorWithException<? extends E> after) {
113                requireNonNull(after);
114                return t -> after.applyAsDouble(applyAsDouble(t));
115        }
116
117        /**
118         * Returns a unary operator that always returns its input argument.
119         *
120         * @return a unary operator that always returns its input argument
121         *
122         * @param <E>
123         *            the exception that may be thrown
124         */
125        static <E extends Exception> DoubleUnaryOperatorWithException<E> identity() {
126                return t -> t;
127        }
128
129        /**
130         * Returns a function that always throw exception.
131         *
132         * @param exceptionBuilder
133         *            the supplier to create the exception
134         * @param <E>
135         *            the type of the exception
136         * @return a function that always throw exception
137         */
138        static <E extends Exception> DoubleUnaryOperatorWithException<E> failing(Supplier<E> exceptionBuilder) {
139                return operand -> {
140                        throw exceptionBuilder.get();
141                };
142        }
143
144        /**
145         * Converts a {@code DoubleUnaryOperatorException} to a
146         * {@code DoubleUnaryOperator} that wraps exception to {@code RuntimeException}.
147         *
148         * @param function
149         *            to be unchecked
150         * @param <E>
151         *            the type of the potential exception
152         * @return the unchecked function
153         * @see #uncheck()
154         * @see #unchecked(DoubleUnaryOperatorWithException, Function)
155         * @throws NullPointerException
156         *             if function is null
157         */
158        static <E extends Exception> DoubleUnaryOperator unchecked(DoubleUnaryOperatorWithException<E> function) {
159                return verifyFunction(function).uncheck();
160        }
161
162        /**
163         * Converts a {@code DoubleUnaryOperatorWithException} to a
164         * {@code DoubleUnaryOperator} that wraps exception to {@code RuntimeException}
165         * by using the provided mapping function.
166         *
167         * @param function
168         *            the be unchecked
169         * @param exceptionMapper
170         *            a function to convert the exception to the runtime exception.
171         * @param <E>
172         *            the type of the potential exception
173         * @return the unchecked function
174         * @see #uncheck()
175         * @see #unchecked(DoubleUnaryOperatorWithException)
176         * @throws NullPointerException
177         *             if function or exceptionMapper is null
178         */
179        static <E extends Exception> DoubleUnaryOperator unchecked(DoubleUnaryOperatorWithException<E> function,
180                        Function<Exception, RuntimeException> exceptionMapper) {
181                verifyFunction(function);
182                verifyExceptionMapper(exceptionMapper);
183                return new DoubleUnaryOperatorWithException<E>() {
184
185                        @Override
186                        public double applyAsDouble(double operand) throws E {
187                                return function.applyAsDouble(operand);
188                        }
189
190                        @Override
191                        public Function<Exception, RuntimeException> exceptionMapper() {
192                                return exceptionMapper;
193                        }
194
195                }.uncheck();
196        }
197
198        /**
199         * Converts a {@code DoubleUnaryOperatorWithException} to a lifted
200         * {@code DoubleUnaryOperator} using {@code 0} as return value in case of error.
201         *
202         * @param function
203         *            to be lifted
204         * @param <E>
205         *            the type of the potential exception
206         * @return the lifted function
207         * @see #lift()
208         * @throws NullPointerException
209         *             if function is null
210         */
211        static <E extends Exception> DoubleUnaryOperator lifted(DoubleUnaryOperatorWithException<E> function) {
212                return verifyFunction(function).lift();
213        }
214
215        /**
216         * Converts a {@code DoubleUnaryOperatorWithException} to a lifted
217         * {@code DoubleUnaryOperator} returning {@code 0} in case of exception.
218         *
219         * @param function
220         *            to be lifted
221         * @param <E>
222         *            the type of the potential exception
223         * @return the lifted function
224         * @see #ignore()
225         * @throws NullPointerException
226         *             if function is null
227         */
228        static <E extends Exception> DoubleUnaryOperator ignored(DoubleUnaryOperatorWithException<E> function) {
229                return verifyFunction(function).ignore();
230        }
231
232        /**
233         * Converts a {@code DoubleUnaryOperatorWithException} to a lifted
234         * {@code DoubleUnaryOperator} returning a default value in case of exception.
235         *
236         * @param function
237         *            to be lifted
238         * @param defaultValue
239         *            the default value in case of exception
240         * @param <E>
241         *            the type of the potential exception
242         * @return the lifted function
243         * @see #ignore()
244         * @see #ignored(DoubleUnaryOperatorWithException)
245         * @throws NullPointerException
246         *             if function is null
247         * @since 3.0.0
248         */
249        static <E extends Exception> DoubleUnaryOperator ignored(DoubleUnaryOperatorWithException<E> function,
250                        double defaultValue) {
251                verifyFunction(function);
252                return new DoubleUnaryOperatorWithException<E>() {
253
254                        @Override
255                        public double applyAsDouble(double operand) throws E {
256                                return function.applyAsDouble(operand);
257                        }
258
259                        @Override
260                        public double defaultValue() {
261                                return defaultValue;
262                        }
263
264                }.ignore();
265        }
266
267}