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