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.verifyConsumer; 023import static ch.powerunit.extensions.exceptions.Constants.verifyExceptionMapper; 024import static java.util.Objects.requireNonNull; 025 026import java.util.concurrent.CompletionStage; 027import java.util.function.BiConsumer; 028import java.util.function.BiFunction; 029import java.util.function.Function; 030import java.util.function.Supplier; 031 032/** 033 * Represents an operation that accepts two input arguments and returns no 034 * result and may throw exception. Unlike most other functional interfaces, 035 * {@code BiConsumerWithException} is expected to operate via side-effects. 036 * 037 * <h3>General contract</h3> 038 * <ul> 039 * <li><b>{@link #accept(Object, Object) void accept(T t,U u) throws 040 * E}</b> - The functional method.</li> 041 * <li><b>uncheck</b> - Return a {@code Biconsumer<T,U>}</li> 042 * <li><b>lift</b> - Return a {@code Biconsumer<T,U>}</li> 043 * <li><b>ignore</b> - Return a {@code Biconsumer<T,U>}</li> 044 * </ul> 045 * 046 * @see BiConsumer 047 * @param <T> 048 * the type of the first argument to the operation 049 * @param <U> 050 * the type of the second argument to the operation 051 * @param <E> 052 * the type of the potential exception of the operation 053 */ 054@FunctionalInterface 055public interface BiConsumerWithException<T, U, E extends Exception> extends 056 NoReturnExceptionHandlerSupport<BiConsumer<T, U>, BiFunction<T, U, CompletionStage<Void>>, BiConsumerWithException<T, U, E>> { 057 058 /** 059 * Performs this operation on the given arguments. 060 * 061 * @param t 062 * the first input argument 063 * @param u 064 * the second input argument 065 * @throws E 066 * any exception 067 * @see BiConsumer#accept(Object,Object) 068 */ 069 void accept(T t, U u) throws E; 070 071 /** 072 * Converts this {@code BiConsumerWithException} to a {@code BiConsumer} that 073 * wraps exception into {@code RuntimeException}. 074 * 075 * @return the unchecked operation 076 * @see #unchecked(BiConsumerWithException) 077 * @see #unchecked(BiConsumerWithException, Function) 078 * @see BiConsumer 079 */ 080 @Override 081 default BiConsumer<T, U> uncheck() { 082 return (t, u) -> NoReturnExceptionHandlerSupport.unchecked(() -> accept(t, u), throwingHandler()); 083 } 084 085 /** 086 * Converts this {@code BiConsumerWithException} to a <i>lifted</i> 087 * {@code BiConsumer} that ignore exception. 088 * 089 * @return the operation that ignore error 090 * @see #ignored(BiConsumerWithException) 091 * @see BiConsumer 092 */ 093 @Override 094 default BiConsumer<T, U> ignore() { 095 return (t, u) -> NoReturnExceptionHandlerSupport.unchecked(() -> accept(t, u), notThrowingHandler()); 096 } 097 098 /** 099 * Converts this {@code BiConsumerWithException} to a <i>staged</i> 100 * {@code BiFunction} that return a {@code CompletionStage}. 101 * 102 * @return the staged operation. 103 * @since 1.1.0 104 */ 105 @Override 106 default BiFunction<T, U, CompletionStage<Void>> stage() { 107 return (t, u) -> NoReturnExceptionHandlerSupport.staged(() -> accept(t, u)); 108 } 109 110 /** 111 * Returns a composed {@code BiConsumerWithException} that performs, in 112 * sequence, this operation followed by the {@code after} operation. If 113 * performing either operation throws an exception, it is relayed to the caller 114 * of the composed operation. If performing this operation throws an exception, 115 * the {@code after} operation will not be performed. 116 * 117 * @param after 118 * the operation to perform after this operation 119 * @return a composed {@code BiConsumerWithException} that performs in sequence 120 * this operation followed by the {@code after} operation 121 * @throws NullPointerException 122 * if {@code after} is null 123 * @see BiConsumer#andThen(BiConsumer) 124 */ 125 default BiConsumerWithException<T, U, E> andThen(BiConsumerWithException<? super T, ? super U, ? extends E> after) { 126 requireNonNull(after); 127 return (T t, U u) -> { 128 accept(t, u); 129 after.accept(t, u); 130 }; 131 } 132 133 /** 134 * Returns a {@code BiConsumerWithException} that always throw exception. 135 * 136 * @param exceptionBuilder 137 * the supplier to create the exception 138 * @param <T> 139 * the type of the first argument to the operation 140 * @param <U> 141 * the type of the second argument to the operation 142 * @param <E> 143 * the type of the potential exception of the operation 144 * 145 * @return an operation that always throw exception 146 */ 147 static <T, U, E extends Exception> BiConsumerWithException<T, U, E> failing(Supplier<E> exceptionBuilder) { 148 return (t, u) -> { 149 throw exceptionBuilder.get(); 150 }; 151 } 152 153 /** 154 * Converts a {@code BiConsumerWithException} to a {@code BiConsumer} that wraps 155 * exception to {@code RuntimeException}. 156 * <p> 157 * For example : 158 * 159 * <pre> 160 * BiConsumerWithException<String, String, IOException> consumerThrowingException = ...; 161 * 162 * BiConsumer<String, String> consumerThrowingRuntimeException = 163 * ConsumerWithException.unchecked(consumerThrowingException); 164 * 165 * myMap.forEach(consumerThrowingRuntimeException); 166 * </pre> 167 * 168 * In case of exception inside {@code consumerThrowingRuntimeException} an 169 * instance of {@code WrappedException} with the original exception as cause 170 * will be thrown. 171 * 172 * @param consumer 173 * to be unchecked 174 * @param <T> 175 * the type of the first argument to the operation 176 * @param <U> 177 * the type of the second argument to the operation 178 * @param <E> 179 * the type of the potential exception of the operation 180 * @return the unchecked exception 181 * @see #uncheck() 182 * @see #unchecked(BiConsumerWithException, Function) 183 * @throws NullPointerException 184 * if consumer is null 185 */ 186 static <T, U, E extends Exception> BiConsumer<T, U> unchecked(BiConsumerWithException<T, U, E> consumer) { 187 return verifyConsumer(consumer).uncheck(); 188 } 189 190 /** 191 * Converts a {@code BiConsumerWithException} to a {@code BiConsumer} that wraps 192 * exception to {@code RuntimeException} by using the provided mapping function. 193 * 194 * <p> 195 * For example : 196 * 197 * <pre> 198 * BiConsumerWithException<String, String, IOException> consumerThrowingException = ...; 199 * 200 * BiConsumer<String, String> consumerThrowingRuntimeException = 201 * ConsumerWithException.unchecked( 202 * consumerThrowingException, 203 * IllegalArgumentException::new); 204 * 205 * myMap.forEach(consumerThrowingRuntimeException) 206 * </pre> 207 * 208 * In case of exception inside {@code consumerThrowingRuntimeException} an 209 * instance of {@code IllegalArgumentException} with the original exception as 210 * cause will be thrown. 211 * 212 * @param consumer 213 * the be unchecked 214 * @param exceptionMapper 215 * a function to convert the exception to the runtime exception. 216 * @param <T> 217 * the type of the first argument to the operation 218 * @param <U> 219 * the type of the second argument to the operation 220 * @param <E> 221 * the type of the potential exception of the operation 222 * @return the unchecked exception 223 * @see #uncheck() 224 * @see #unchecked(BiConsumerWithException) 225 * @throws NullPointerException 226 * if consumer or exceptionMapper is null 227 */ 228 static <T, U, E extends Exception> BiConsumer<T, U> unchecked(BiConsumerWithException<T, U, E> consumer, 229 Function<Exception, RuntimeException> exceptionMapper) { 230 verifyConsumer(consumer); 231 verifyExceptionMapper(exceptionMapper); 232 return new BiConsumerWithException<T, U, E>() { 233 234 @Override 235 public void accept(T t, U u) throws E { 236 consumer.accept(t, u); 237 } 238 239 @Override 240 public Function<Exception, RuntimeException> exceptionMapper() { 241 return exceptionMapper; 242 } 243 244 }.uncheck(); 245 } 246 247 /** 248 * Converts a {@code BiConsumerWithException} to a lifted {@code BiConsumer} 249 * ignoring exception. 250 * <p> 251 * For example : 252 * 253 * <pre> 254 * BiConsumerWithException<String, String, IOException> consumerThrowingException = ...; 255 * 256 * BiConsumer<String, String> consumerThrowingRuntimeException = 257 * ConsumerWithException.lifted(consumerThrowingException); 258 * 259 * myMap.forEach(consumerThrowingRuntimeException); 260 * </pre> 261 * 262 * In case of exception inside {@code consumerThrowingRuntimeException} the 263 * exception will be ignored. 264 * 265 * @param consumer 266 * to be lifted 267 * @param <T> 268 * the type of the first argument to the operation 269 * @param <U> 270 * the type of the second argument to the operation 271 * @param <E> 272 * the type of the potential exception of the operation 273 * @return the lifted operation 274 * @see #lift() 275 * @throws NullPointerException 276 * if consumer is null 277 */ 278 static <T, U, E extends Exception> BiConsumer<T, U> lifted(BiConsumerWithException<T, U, E> consumer) { 279 return verifyConsumer(consumer).lift(); 280 } 281 282 /** 283 * Converts a {@code BiConsumerWithException} to a lifted {@code BiConsumer} 284 * ignoring exception. 285 * <p> 286 * For example : 287 * 288 * <pre> 289 * BiConsumerWithException<String, String, IOException> consumerThrowingException = ...; 290 * 291 * BiConsumer<String, String> consumerThrowingRuntimeException = 292 * ConsumerWithException.ignored(consumerThrowingException); 293 * 294 * myMap.forEach(consumerThrowingRuntimeException); 295 * </pre> 296 * 297 * In case of exception inside {@code consumerThrowingRuntimeException} the 298 * exception will be ignored. 299 * 300 * @param consumer 301 * to be lifted 302 * @param <T> 303 * the type of the first argument to the operation 304 * @param <U> 305 * the type of the second argument to the operation 306 * @param <E> 307 * the type of the potential exception of the operation 308 * @return the lifted operation 309 * @see #ignore() 310 * @throws NullPointerException 311 * if consumer is null 312 */ 313 static <T, U, E extends Exception> BiConsumer<T, U> ignored(BiConsumerWithException<T, U, E> consumer) { 314 return verifyConsumer(consumer).ignore(); 315 } 316 317 /** 318 * Converts a {@code BiConsumerWithException} to a staged {@code BiFunction}. 319 * 320 * @param consumer 321 * to be staged 322 * @param <T> 323 * the type of the first argument to the operation 324 * @param <U> 325 * the type of the second argument to the operation 326 * @param <E> 327 * the type of the potential exception 328 * @return the staged operation 329 * @throws NullPointerException 330 * if consumer is null 331 * @since 1.1.0 332 */ 333 static <T, U, E extends Exception> BiFunction<T, U, CompletionStage<Void>> staged( 334 BiConsumerWithException<T, U, E> consumer) { 335 return verifyConsumer(consumer).stage(); 336 } 337 338 /** 339 * Converts a {@code BiConsumerWithException} to a 340 * {@code BiFunctionWithException} returning {@code null}. 341 * 342 * @param consumer 343 * to be converter 344 * @param <T> 345 * the type of the first argument to the operation 346 * @param <U> 347 * the type of the second argument to the operation 348 * @param <R> 349 * the type of the return value of the function 350 * @param <E> 351 * the type of the potential exception of the operation 352 * @return the function 353 * @throws NullPointerException 354 * if consumer is null 355 */ 356 static <T, U, R, E extends Exception> BiFunctionWithException<T, U, R, E> asBiFunction( 357 BiConsumerWithException<T, U, E> consumer) { 358 return verifyConsumer(consumer).asBiFunction(); 359 } 360 361 /** 362 * Converts a {@code BiConsumerWithException} to a 363 * {@code BiFunctionWithException} returning {@code null}. 364 * 365 * @param <R> 366 * the type of the return value of the function 367 * @return the function 368 * @since 1.2.0 369 */ 370 default <R> BiFunctionWithException<T, U, R, E> asBiFunction() { 371 return (t, u) -> { 372 accept(t, u); 373 return null; 374 }; 375 } 376 377}