001/* 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017package org.apache.juneau.commons.function; 018 019import static org.apache.juneau.commons.utils.AssertionUtils.*; 020import static org.apache.juneau.commons.utils.ThrowableUtils.*; 021 022/** 023 * A functional interface representing an operation that accepts four arguments, returns no result, and may throw a checked exception. 024 * 025 * <p> 026 * This interface extends {@link Consumer4} to allow the functional method 027 * to throw checked exceptions. The default {@link #apply(Object, Object, Object, Object)} method wraps any checked exceptions in a 028 * {@link RuntimeException}, making it compatible with standard {@link Consumer4} usage while still allowing 029 * the implementation to throw checked exceptions via {@link #acceptThrows(Object, Object, Object, Object)}. 030 * 031 * <h5 class='section'>Features:</h5> 032 * <ul class='spaced-list'> 033 * <li>Functional interface - can be used with lambda expressions and method references 034 * <li>Exception support - allows checked exceptions to be thrown via {@link #acceptThrows(Object, Object, Object, Object)} 035 * <li>Compatible with Consumer4 - implements {@link Consumer4#apply(Object, Object, Object, Object)} by wrapping exceptions 036 * <li>Dual interface - can be used as both Consumer4 and ThrowingConsumer4 037 * </ul> 038 * 039 * <h5 class='section'>Use Cases:</h5> 040 * <ul class='spaced-list'> 041 * <li>Four-argument operations that may throw I/O exceptions 042 * <li>Validation operations that may throw validation exceptions 043 * <li>Side-effect operations that may fail with checked exceptions 044 * <li>Operations that need to propagate checked exceptions 045 * </ul> 046 * 047 * <h5 class='section'>Usage:</h5> 048 * <p class='bjava'> 049 * <jc>// Lambda with exception</jc> 050 * ThrowingConsumer4<String,Integer,Boolean,Double> <jv>fileWriter</jv> = (<jv>path</jv>, <jv>content</jv>, <jv>append</jv>, <jv>timeout</jv>) -> { 051 * <jk>if</jk> (<jv>append</jv>) { 052 * Files.write(Paths.get(<jv>path</jv>), <jv>content</jv>.getBytes(), StandardOpenOption.APPEND); 053 * } <jk>else</jk> { 054 * Files.write(Paths.get(<jv>path</jv>), <jv>content</jv>.getBytes()); 055 * } 056 * }; 057 * 058 * <jc>// Using acceptThrows to get checked exception</jc> 059 * <jk>try</jk> { 060 * <jv>fileWriter</jv>.acceptThrows(<js>"/tmp/output.txt"</js>, <js>"Hello World"</js>, <jk>true</jk>, 5.0); 061 * } <jk>catch</jk> (IOException <jv>e</jv>) { 062 * <jc>// Handle checked exception</jc> 063 * } 064 * 065 * <jc>// Using apply wraps exception in RuntimeException</jc> 066 * <jv>fileWriter</jv>.apply(<js>"/tmp/output.txt"</js>, <js>"Hello World"</js>, <jk>true</jk>, 5.0); <jc>// May throw RuntimeException</jc> 067 * </p> 068 * 069 * <h5 class='section'>Exception Handling:</h5> 070 * <ul class='spaced-list'> 071 * <li>{@link #acceptThrows(Object, Object, Object, Object)} - Throws checked exceptions directly 072 * <li>{@link #apply(Object, Object, Object, Object)} - Wraps checked exceptions in {@link RuntimeException} 073 * <li>Use {@code acceptThrows} when you need to handle specific checked exceptions 074 * <li>Use {@code apply} when you want standard Consumer4 behavior 075 * </ul> 076 * 077 * <h5 class='section'>See Also:</h5><ul> 078 * <li class='jc'>{@link ThrowingConsumer} - Single-argument consumer that throws exceptions 079 * <li class='jc'>{@link ThrowingConsumer2} - Two-argument consumer that throws exceptions 080 * <li class='jc'>{@link ThrowingConsumer3} - Three-argument consumer that throws exceptions 081 * <li class='jc'>{@link ThrowingConsumer5} - Five-argument consumer that throws exceptions 082 * <li class='link'><a class="doclink" href="https://juneau.apache.org/docs/topics/JuneauCommonsBasics">juneau-commons Basics</a> 083 * </ul> 084 * 085 * @param <A> The type of the first argument to the operation. 086 * @param <B> The type of the second argument to the operation. 087 * @param <C> The type of the third argument to the operation. 088 * @param <D> The type of the fourth argument to the operation. 089 */ 090@FunctionalInterface 091public interface ThrowingConsumer4<A,B,C,D> extends Consumer4<A,B,C,D> { 092 093 /** 094 * Performs this operation on the given arguments, wrapping any checked exceptions in a {@link RuntimeException}. 095 * 096 * <p> 097 * This is the default implementation that makes this interface compatible with {@link Consumer4}. 098 * It calls {@link #acceptThrows(Object, Object, Object, Object)} and wraps any checked exceptions. 099 * 100 * @param a The first operation argument. 101 * @param b The second operation argument. 102 * @param c The third operation argument. 103 * @param d The fourth operation argument. 104 * @throws RuntimeException if {@link #acceptThrows(Object, Object, Object, Object)} throws a checked exception. 105 */ 106 @Override 107 default void apply(A a, B b, C c, D d) { 108 try { 109 acceptThrows(a, b, c, d); 110 } catch (Exception e) { 111 throw toRex(e); 112 } 113 } 114 115 /** 116 * Returns a composed {@link ThrowingConsumer4} that performs, in sequence, this operation followed by the {@code after} operation. 117 * 118 * <p> 119 * This method enables operation composition, allowing you to chain multiple operations together. 120 * If performing either operation throws an exception, it is relayed to the caller of the composed operation. 121 * If performing this operation throws an exception, the {@code after} operation will not be performed. 122 * 123 * @param after The operation to perform after this operation. Must not be <jk>null</jk>. 124 * @return A composed {@link ThrowingConsumer4} that performs in sequence this operation followed by the {@code after} operation. 125 * @throws NullPointerException if {@code after} is <jk>null</jk>. 126 */ 127 default ThrowingConsumer4<A,B,C,D> andThen(ThrowingConsumer4<? super A,? super B,? super C,? super D> after) { // NOSONAR - false positive on generics 128 assertArgNotNull("after", after); 129 return (A a, B b, C c, D d) -> { 130 acceptThrows(a, b, c, d); 131 after.acceptThrows(a, b, c, d); 132 }; 133 } 134 135 /** 136 * Performs this operation on the given arguments, potentially throwing a checked exception. 137 * 138 * <p> 139 * This is the functional method that implementations must provide. It allows checked exceptions 140 * to be thrown directly, unlike the standard {@link Consumer4#apply(Object, Object, Object, Object)} method. 141 * 142 * <h5 class='section'>Example:</h5> 143 * <p class='bjava'> 144 * ThrowingConsumer4<String,Integer,Boolean,Double> <jv>validator</jv> = (<jv>name</jv>, <jv>age</jv>, <jv>active</jv>, <jv>score</jv>) -> { 145 * <jk>if</jk> (<jv>name</jv> == <jk>null</jk> || <jv>name</jv>.isEmpty()) { 146 * <jk>throw new</jk> ValidationException(<js>"Name cannot be empty"</js>); 147 * } 148 * <jk>if</jk> (<jv>age</jv> < 0) { 149 * <jk>throw new</jk> ValidationException(<js>"Age cannot be negative"</js>); 150 * } 151 * }; 152 * 153 * <jk>try</jk> { 154 * <jv>validator</jv>.acceptThrows(<js>""</js>, -1, <jk>true</jk>, 0.0); 155 * } <jk>catch</jk> (ValidationException <jv>e</jv>) { 156 * <jc>// Handle checked exception</jc> 157 * } 158 * </p> 159 * 160 * @param a The first operation argument. 161 * @param b The second operation argument. 162 * @param c The third operation argument. 163 * @param d The fourth operation argument. 164 * @throws Exception If an error occurs during operation execution. 165 */ 166 void acceptThrows(A a, B b, C c, D d) throws Exception; 167} 168