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.Optional; 027import java.util.concurrent.CompletionStage; 028import java.util.function.BiFunction; 029import java.util.function.Function; 030import java.util.function.Supplier; 031 032/** 033 * Represents a function that accepts two arguments, may thrown exception and 034 * produces a result. This is the two-arity specialization of 035 * {@link FunctionWithException}. 036 * 037 * <h3>General contract</h3> 038 * <ul> 039 * <li><b>{@link #apply(Object, Object) R apply(T t, U u) throws 040 * E}</b> - The functional method.</li> 041 * <li><b>uncheck</b> - Return a {@code BiFunction<T,U,R>}</li> 042 * <li><b>lift</b> - Return a 043 * {@code BiFunction<T,U,<Optional<R>>}</li> 044 * <li><b>ignore</b> - Return a {@code BiFunction<T,U,R>}</li> 045 * </ul> 046 * 047 * @see BiFunction 048 * @param <T> 049 * the type of the first argument to the function 050 * @param <U> 051 * the type of the second argument to the function 052 * @param <R> 053 * the type of the result of the function 054 * @param <E> 055 * the type of the potential exception of the function 056 */ 057@FunctionalInterface 058public interface BiFunctionWithException<T, U, R, E extends Exception> extends 059 ObjectReturnExceptionHandlerSupport<BiFunction<T, U, R>, BiFunction<T, U, Optional<R>>, BiFunction<T, U, CompletionStage<R>>, R, BiFunctionWithException<T, U, R, E>> { 060 061 /** 062 * Applies this function to the given arguments. 063 * 064 * @param t 065 * the first function argument 066 * @param u 067 * the second function argument 068 * @return the function result 069 * @throws E 070 * any exception 071 * @see BiFunction#apply(Object,Object) 072 */ 073 R apply(T t, U u) throws E; 074 075 /** 076 * Converts this {@code BiFunctionWithException} to a {@code BiFunction} that 077 * wraps exception to {@code RuntimeException}. 078 * 079 * @return the unchecked function 080 * @see #unchecked(BiFunctionWithException) 081 * @see #unchecked(BiFunctionWithException, Function) 082 * @see BiFunction 083 */ 084 @Override 085 default BiFunction<T, U, R> uncheck() { 086 return (t, u) -> ObjectReturnExceptionHandlerSupport.unchecked(() -> apply(t, u), throwingHandler()); 087 088 } 089 090 /** 091 * Converts this {@code BiFunctionWithException} to a lifted {@code BiFunction} 092 * using {@code Optional} as return value. 093 * 094 * @return the lifted function 095 * @see #lifted(BiFunctionWithException) 096 * @see BiFunction 097 */ 098 @Override 099 default BiFunction<T, U, Optional<R>> lift() { 100 return (t, u) -> ObjectReturnExceptionHandlerSupport.unchecked(() -> Optional.ofNullable(apply(t, u)), 101 notThrowingHandler()); 102 } 103 104 /** 105 * Converts this {@code BiFunctionWithException} to a lifted {@code BiFunction} 106 * returning {@code null} (or the value redefined by the method 107 * {@link #defaultValue()}) in case of exception. 108 * 109 * @return the function that ignore error 110 * @see #ignored(BiFunctionWithException) 111 * @see BiFunction 112 */ 113 @Override 114 default BiFunction<T, U, R> ignore() { 115 return lift().andThen(o -> o.orElse(defaultValue())); 116 } 117 118 /** 119 * Convert this {@code BiFunctionWithException} to a lifted {@code BiFunction} 120 * that uses {@code CompletionStage} as return value. 121 * 122 * @return the lifted function 123 * @see #staged(BiFunctionWithException) 124 * @see BiFunction 125 * @see CompletionStage 126 */ 127 @Override 128 default BiFunction<T, U, CompletionStage<R>> stage() { 129 return (t, u) -> ObjectReturnExceptionHandlerSupport.staged(() -> apply(t, u)); 130 } 131 132 /** 133 * Returns a composed {@code FunctionWithException} that first applies this 134 * {@code FunctionWithException} to its input, and then applies the 135 * {@code after} {@code FunctionWithException} to the result. If evaluation of 136 * either {@code FunctionWithException} throws an exception, it is relayed to 137 * the caller of the composed function. 138 * 139 * @param <V> 140 * the type of output of the {@code after} 141 * {@code FunctionWithException}, and of the composed 142 * {@code FunctionWithException} 143 * @param after 144 * the function to apply after this {@code FunctionWithException} is 145 * applied 146 * @return a composed function that first applies this function and then applies 147 * the {@code after} function 148 * @throws NullPointerException 149 * if after is null 150 * 151 * @see BiFunction#andThen(Function) 152 */ 153 default <V> BiFunctionWithException<T, U, V, E> andThen( 154 FunctionWithException<? super R, ? extends V, ? extends E> after) { 155 requireNonNull(after); 156 return (T t, U u) -> after.apply(apply(t, u)); 157 } 158 159 /** 160 * Returns a {@code FunctionWithException} that always throw exception. 161 * 162 * @param exceptionBuilder 163 * the supplier to create the exception 164 * @param <T> 165 * the type of the first argument to the function 166 * @param <U> 167 * the type of the second argument to the function 168 * @param <R> 169 * the type of the result of the function 170 * @param <E> 171 * the type of the exception 172 * @return a function that always throw exception 173 */ 174 static <T, U, R, E extends Exception> BiFunctionWithException<T, U, R, E> failing(Supplier<E> exceptionBuilder) { 175 return (t, u) -> { 176 throw exceptionBuilder.get(); 177 }; 178 } 179 180 /** 181 * Converts a {@code BiFunctionWithException} to a {@code BiFunction} that 182 * convert exception to {@code RuntimeException}. 183 * <p> 184 * For example : 185 * 186 * <pre> 187 * BiFunction<String, String, String> biFunctionThrowingRuntimeException = BiFunctionWithException 188 * .unchecked(biFouctionThrowingException); 189 * </pre> 190 * 191 * Will generate a {@code BiFunction} throwing {@code RuntimeException} in case 192 * of error. 193 * 194 * @param function 195 * to be unchecked 196 * @param <T> 197 * the type of the first argument to the function 198 * @param <U> 199 * the type of the second argument to the function 200 * @param <R> 201 * the type of the result of the function 202 * @param <E> 203 * the type of the potential exception 204 * @return the unchecked exception 205 * @see #uncheck() 206 * @see #unchecked(BiFunctionWithException, Function) 207 * @throws NullPointerException 208 * if function is null 209 */ 210 static <T, U, R, E extends Exception> BiFunction<T, U, R> unchecked(BiFunctionWithException<T, U, R, E> function) { 211 return verifyFunction(function).uncheck(); 212 } 213 214 /** 215 * Converts a {@code BiFunctionWithException} to a {@code BiFunction} that 216 * convert exception to {@code RuntimeException} by using the provided mapping 217 * function. 218 * <p> 219 * For example : 220 * 221 * <pre> 222 * BiFunction<String, String, String> functionThrowingRuntimeException = BiFunctionWithException 223 * .unchecked(fonctionThrowingException, IllegalArgumentException::new); 224 * </pre> 225 * 226 * Will generate a {@code BiFunction} throwing {@code IllegalArgumentException} 227 * in case of error. 228 * 229 * @param function 230 * the be unchecked 231 * @param exceptionMapper 232 * a function to convert the exception to the runtime exception. 233 * @param <T> 234 * the type of the first argument to the function 235 * @param <U> 236 * the type of the second argument to the function 237 * @param <R> 238 * the type of the result of the function 239 * @param <E> 240 * the type of the potential exception 241 * @return the unchecked exception 242 * @see #uncheck() 243 * @see #unchecked(BiFunctionWithException) 244 * @throws NullPointerException 245 * if function or exceptionMapper is null 246 */ 247 static <T, U, R, E extends Exception> BiFunction<T, U, R> unchecked(BiFunctionWithException<T, U, R, E> function, 248 Function<Exception, RuntimeException> exceptionMapper) { 249 verifyFunction(function); 250 verifyExceptionMapper(exceptionMapper); 251 return new BiFunctionWithException<T, U, R, E>() { 252 253 @Override 254 public R apply(T t, U u) throws E { 255 return function.apply(t, u); 256 } 257 258 @Override 259 public Function<Exception, RuntimeException> exceptionMapper() { 260 return exceptionMapper; 261 } 262 263 }.uncheck(); 264 } 265 266 /** 267 * Converts a {@code BiFunctionWithException} to a lifted {@code BiFunction} 268 * using {@code Optional} as return value. 269 * 270 * @param function 271 * to be lifted 272 * @param <T> 273 * the type of the first argument to the function 274 * @param <U> 275 * the type of the second argument to the function 276 * @param <R> 277 * the type of the result of the function 278 * @param <E> 279 * the type of the potential exception 280 * @return the lifted function 281 * @see #lift() 282 * @throws NullPointerException 283 * if function is null 284 */ 285 static <T, U, R, E extends Exception> BiFunction<T, U, Optional<R>> lifted( 286 BiFunctionWithException<T, U, R, E> function) { 287 return verifyFunction(function).lift(); 288 } 289 290 /** 291 * Converts a {@code BiFunctionWithException} to a lifted {@code BiFunction} 292 * returning {@code null} in case of exception. 293 * 294 * @param function 295 * to be lifted 296 * @param <T> 297 * the type of the first argument to the function 298 * @param <U> 299 * the type of the second argument to the function 300 * @param <R> 301 * the type of the result of the function 302 * @param <E> 303 * the type of the potential exception 304 * @return the lifted function 305 * @see #ignore() 306 * @throws NullPointerException 307 * if function is null 308 */ 309 static <T, U, R, E extends Exception> BiFunction<T, U, R> ignored(BiFunctionWithException<T, U, R, E> function) { 310 return verifyFunction(function).ignore(); 311 } 312 313 /** 314 * Converts a {@code BiFunctionWithException} to a lifted {@code BiFunction} 315 * returning a default in case of exception. 316 * 317 * @param function 318 * to be lifted 319 * @param defaultValue 320 * the value to be returned in case of error 321 * @param <T> 322 * the type of the first argument to the function 323 * @param <U> 324 * the type of the second argument to the function 325 * @param <R> 326 * the type of the result of the function 327 * @param <E> 328 * the type of the potential exception 329 * @return the lifted function 330 * @see #ignore() 331 * @see #ignored(BiFunctionWithException) 332 * @throws NullPointerException 333 * if function is null 334 * @since 3.0.0 335 */ 336 static <T, U, R, E extends Exception> BiFunction<T, U, R> ignored(BiFunctionWithException<T, U, R, E> function, 337 R defaultValue) { 338 verifyFunction(function); 339 return new BiFunctionWithException<T, U, R, E>() { 340 341 @Override 342 public R apply(T t, U u) throws E { 343 return function.apply(t, u); 344 } 345 346 @Override 347 public R defaultValue() { 348 return defaultValue; 349 } 350 351 }.ignore(); 352 353 } 354 355 /** 356 * Convert this {@code BiFunctionWithException} to a lifted {@code BiFunction} 357 * return {@code CompletionStage} as return value. 358 * 359 * @param function 360 * to be lifted 361 * @param <T> 362 * the type of the first argument to the function 363 * @param <U> 364 * the type of the second argument to the function 365 * @param <R> 366 * the type of the result of the function 367 * @param <E> 368 * the type of the potential exception 369 * @return the lifted function 370 * @see #stage() 371 * @throws NullPointerException 372 * if function is null 373 */ 374 static <T, U, R, E extends Exception> BiFunction<T, U, CompletionStage<R>> staged( 375 BiFunctionWithException<T, U, R, E> function) { 376 return verifyFunction(function).stage(); 377 } 378 379 /** 380 * Converts a {@code BiFunctionWithException} to a 381 * {@code BiConsumerWithException}. 382 * 383 * @param function 384 * to be converter 385 * @param <T> 386 * the type of the first argument to the operation 387 * @param <U> 388 * the type of the second argument to the operation 389 * @param <R> 390 * the type of the return value of the function 391 * @param <E> 392 * the type of the potential exception of the operation 393 * @return the consumer 394 * @throws NullPointerException 395 * if function is null 396 * @since 1.2.0 397 */ 398 static <T, U, R, E extends Exception> BiConsumerWithException<T, U, E> asBiConsumer( 399 BiFunctionWithException<T, U, R, E> function) { 400 return verifyFunction(function).asBiConsumer(); 401 } 402 403 /** 404 * Converts a {@code BiFunctionWithException} to a 405 * {@code BiConsumerWithException}. 406 * 407 * @return the consumer 408 * @since 1.2.0 409 */ 410 default BiConsumerWithException<T, U, E> asBiConsumer() { 411 return this::apply; 412 } 413 414 /** 415 * Converts a {@code BiFunctionWithException} to a 416 * {@code FunctionWithException}. 417 * 418 * @param function 419 * to be converter 420 * 421 * @param u 422 * the second parameter of the {@code BiFunctionWithException} that 423 * will be used inside the new {code FunctionWithException}. 424 * @param <T> 425 * the type of the first argument to the operation 426 * @param <U> 427 * the type of the second argument to the operation 428 * @param <R> 429 * the type of the return value of the function 430 * @param <E> 431 * the type of the potential exception of the operation 432 * @return the consumer 433 * @throws NullPointerException 434 * if function is null 435 * @since 1.2.0 436 */ 437 static <T, U, R, E extends Exception> FunctionWithException<T, R, E> asFunction( 438 BiFunctionWithException<T, U, R, E> function, U u) { 439 return verifyFunction(function).asFunction(u); 440 } 441 442 /** 443 * Converts a {@code BiFunctionWithException} to a 444 * {@code FunctionWithException}. 445 * 446 * @param u 447 * the second parameter of the {@code BiFunctionWithException} that 448 * will be used inside the new {code FunctionWithException}. 449 * 450 * 451 * @return the consumer 452 * @since 1.2.0 453 */ 454 default FunctionWithException<T, R, E> asFunction(U u) { 455 return t -> apply(t, u); 456 } 457 458}