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.verifyOperation; 024import static java.util.Objects.requireNonNull; 025 026import java.util.concurrent.CompletionStage; 027import java.util.function.Function; 028import java.util.function.Supplier; 029 030/** 031 * Represents an operation that accepts no input argument and returns no result 032 * and may throw exception. Unlike most other functional interfaces, 033 * {@code RunnableWithException} is expected to operate via side-effects. 034 * <h3>General contract</h3> 035 * <ul> 036 * <li><b>{@link #run() void run() throws E}</b> - The functional 037 * method.</li> 038 * <li><b>uncheck</b> - Return a {@code Runnable}</li> 039 * <li><b>lift</b> - Return a {@code Runnable}</li> 040 * <li><b>ignore</b> - Return a {@code Runnable}</li> 041 * </ul> 042 * 043 * @see Runnable 044 * @param <E> 045 * the type of the potential exception of the operation 046 */ 047@FunctionalInterface 048public interface RunnableWithException<E extends Exception> 049 extends NoReturnExceptionHandlerSupport<Runnable, Supplier<CompletionStage<Void>>, RunnableWithException<E>> { 050 051 /** 052 * Performs this operation. 053 * 054 * @throws E 055 * any exception 056 * @see Runnable#run() 057 */ 058 void run() throws E; 059 060 /** 061 * Converts this {@code RunnableWithException} to a {@code Runnable} that wraps 062 * exception to {@code RuntimeException}. 063 * 064 * @return the unchecked operation 065 * @see #unchecked(RunnableWithException) 066 * @see #unchecked(RunnableWithException, Function) 067 */ 068 @Override 069 default Runnable uncheck() { 070 return () -> NoReturnExceptionHandlerSupport.unchecked(this::run, throwingHandler()); 071 } 072 073 /** 074 * Converts this {@code RunnableWithException} to a <i>lifted</i> 075 * {@code Runnable} ignoring exception. 076 * 077 * @return the operation that ignore error 078 * @see #ignored(RunnableWithException) 079 */ 080 @Override 081 default Runnable ignore() { 082 return () -> NoReturnExceptionHandlerSupport.unchecked(this::run, notThrowingHandler()); 083 } 084 085 /** 086 * Converts this {@code RunnableWithException} to a <i>staged</i> 087 * {@code Supplier} that return a {@code CompletionStage}. 088 * 089 * @return the staged operation. 090 * @since 1.1.0 091 */ 092 @Override 093 default Supplier<CompletionStage<Void>> stage() { 094 return () -> NoReturnExceptionHandlerSupport.staged(this); 095 } 096 097 /** 098 * Returns a composed {@code RunnableWithException} that performs, in sequence, 099 * this operation followed by the {@code after} operation. If performing either 100 * operation throws an exception, it is relayed to the caller of the composed 101 * operation. If performing this operation throws an exception, the 102 * {@code after} operation will not be performed. 103 * 104 * @param after 105 * the operation to perform after this operation 106 * @return a composed {@code RunnableWithException} that performs in sequence 107 * this operation followed by the {@code after} operation 108 * @throws NullPointerException 109 * if {@code after} is null 110 * @since 1.2.0 111 */ 112 default RunnableWithException<E> andThen(RunnableWithException<? extends E> after) { 113 requireNonNull(after); 114 return () -> { 115 run(); 116 after.run(); 117 }; 118 } 119 120 /** 121 * Returns an operation that always throw exception. 122 * 123 * @param exceptionBuilder 124 * the supplier to create the exception 125 * @param <E> 126 * the type of the exception 127 * @return an operation that always throw exception 128 */ 129 static <E extends Exception> RunnableWithException<E> failing(Supplier<E> exceptionBuilder) { 130 return () -> { 131 throw exceptionBuilder.get(); 132 }; 133 } 134 135 /** 136 * Converts a {@code RunnableWithException} to a {@code Runnable} that wraps 137 * exception to {@code RuntimeException}. 138 * 139 * @param operation 140 * to be unchecked 141 * @param <E> 142 * the type of the potential exception 143 * @return the unchecked exception 144 * @see #uncheck() 145 * @see #unchecked(RunnableWithException, Function) 146 * @throws NullPointerException 147 * if operation is null 148 */ 149 static <E extends Exception> Runnable unchecked(RunnableWithException<E> operation) { 150 return verifyOperation(operation).uncheck(); 151 } 152 153 /** 154 * Converts a {@code RunnableWithException} to a {@code Runnable} that wraps 155 * exception to {@code RuntimeException} by using the provided mapping function. 156 * 157 * @param operation 158 * the be unchecked 159 * @param exceptionMapper 160 * a function to convert the exception to the runtime exception. 161 * @param <E> 162 * the type of the potential exception 163 * @return the unchecked exception 164 * @see #uncheck() 165 * @see #unchecked(RunnableWithException) 166 * @throws NullPointerException 167 * if operation or exceptionMapper is null 168 */ 169 static <E extends Exception> Runnable unchecked(RunnableWithException<E> operation, 170 Function<Exception, RuntimeException> exceptionMapper) { 171 verifyOperation(operation); 172 verifyExceptionMapper(exceptionMapper); 173 return new RunnableWithException<E>() { 174 175 @Override 176 public void run() throws E { 177 operation.run(); 178 } 179 180 @Override 181 public Function<Exception, RuntimeException> exceptionMapper() { 182 return exceptionMapper; 183 } 184 185 }.uncheck(); 186 } 187 188 /** 189 * Converts a {@code RunnableWithException} to a lifted {@code Runnable} 190 * ignoring exception. 191 * 192 * @param operation 193 * to be lifted 194 * @param <E> 195 * the type of the potential exception 196 * @return the lifted operation 197 * @see #lift() 198 * @throws NullPointerException 199 * if operation is null 200 */ 201 static <E extends Exception> Runnable lifted(RunnableWithException<E> operation) { 202 return verifyOperation(operation).lift(); 203 } 204 205 /** 206 * Converts a {@code RunnableWithException} to a lifted {@code Runnable} 207 * ignoring exception. 208 * 209 * @param operation 210 * to be lifted 211 * @param <E> 212 * the type of the potential exception 213 * @return the lifted operation 214 * @see #ignore() 215 * @throws NullPointerException 216 * if operation is null 217 * @since 1.1.0 218 */ 219 static <E extends Exception> Runnable ignored(RunnableWithException<E> operation) { 220 return verifyOperation(operation).ignore(); 221 } 222 223 /** 224 * Converts a {@code RunnableWithException} to a staged {@code Supplier}. 225 * 226 * @param operation 227 * to be staged 228 * @param <E> 229 * the type of the potential exception 230 * @return the staged operation 231 * @throws NullPointerException 232 * if operation is null 233 */ 234 static <E extends Exception> Supplier<CompletionStage<Void>> staged(RunnableWithException<E> operation) { 235 return verifyOperation(operation).stage(); 236 } 237 238 /** 239 * Converts a {@code RunnableWithException} to a {@code FunctionWithException} 240 * returning {@code null} and ignoring input. 241 * 242 * @param operation 243 * to be converted 244 * @param <T> 245 * the type of the input to the operation 246 * @param <R> 247 * the type of the return value 248 * @param <E> 249 * the type of the potential exception 250 * @return the function 251 * @throws NullPointerException 252 * if operation is null 253 * @since 1.2.0 254 */ 255 static <T, R, E extends Exception> FunctionWithException<T, R, E> asFunction(RunnableWithException<E> operation) { 256 verifyOperation(operation); 257 return t -> { 258 operation.run(); 259 return null; 260 }; 261 } 262 263}