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.ThrowableUtils.*; 020 021import java.util.function.*; 022 023/** 024 * A functional interface representing a function that accepts one argument, produces a result, and may throw a checked exception. 025 * 026 * <p> 027 * This interface extends the standard Java {@link Function} to allow the functional method 028 * to throw checked exceptions. The default {@link #apply(Object)} method wraps any checked exceptions in a 029 * {@link RuntimeException}, making it compatible with standard {@link Function} usage while still allowing 030 * the implementation to throw checked exceptions via {@link #applyThrows(Object)}. 031 * 032 * <h5 class='section'>Features:</h5> 033 * <ul class='spaced-list'> 034 * <li>Functional interface - can be used with lambda expressions and method references 035 * <li>Exception support - allows checked exceptions to be thrown via {@link #applyThrows(Object)} 036 * <li>Compatible with Function - implements {@link Function#apply(Object)} by wrapping exceptions 037 * <li>Dual interface - can be used as both Function and ThrowingFunction 038 * </ul> 039 * 040 * <h5 class='section'>Use Cases:</h5> 041 * <ul class='spaced-list'> 042 * <li>Transformations that may throw I/O exceptions 043 * <li>Parsing operations that may throw validation exceptions 044 * <li>Data conversion that may fail with checked exceptions 045 * <li>Operations that need to propagate checked exceptions 046 * </ul> 047 * 048 * <h5 class='section'>Usage:</h5> 049 * <p class='bjava'> 050 * <jc>// Lambda with exception</jc> 051 * ThrowingFunction<String,File> <jv>fileParser</jv> = (<jv>path</jv>) -> { 052 * <jk>if</jk> (! Files.exists(Paths.get(<jv>path</jv>))) { 053 * <jk>throw new</jk> FileNotFoundException(<js>"File not found: "</js> + <jv>path</jv>); 054 * } 055 * <jk>return new</jk> File(<jv>path</jv>); 056 * }; 057 * 058 * <jc>// Using applyThrows to get checked exception</jc> 059 * <jk>try</jk> { 060 * File <jv>file</jv> = <jv>fileParser</jv>.applyThrows(<js>"/path/to/file"</js>); 061 * } <jk>catch</jk> (FileNotFoundException <jv>e</jv>) { 062 * <jc>// Handle checked exception</jc> 063 * } 064 * 065 * <jc>// Using apply wraps exception in RuntimeException</jc> 066 * File <jv>file</jv> = <jv>fileParser</jv>.apply(<js>"/path/to/file"</js>); <jc>// May throw RuntimeException</jc> 067 * </p> 068 * 069 * <h5 class='section'>Exception Handling:</h5> 070 * <ul class='spaced-list'> 071 * <li>{@link #applyThrows(Object)} - Throws checked exceptions directly 072 * <li>{@link #apply(Object)} - Wraps checked exceptions in {@link RuntimeException} 073 * <li>Use {@code applyThrows} when you need to handle specific checked exceptions 074 * <li>Use {@code apply} when you want standard Function behavior 075 * </ul> 076 * 077 * <h5 class='section'>See Also:</h5><ul> 078 * <li class='jc'>{@link ThrowingSupplier} - Supplier that throws exceptions 079 * <li class='jc'>{@link ThrowingConsumer} - Consumer that throws exceptions 080 * <li class='link'><a class="doclink" href="https://juneau.apache.org/docs/topics/JuneauCommons">juneau-commons</a> 081 * </ul> 082 * 083 * @param <T> The type of the input to the function. 084 * @param <R> The type of the result of the function. 085 */ 086@FunctionalInterface 087@SuppressWarnings({ 088 "java:S112" // throws Exception intentional - function may throw any checked exception 089}) 090public interface ThrowingFunction<T,R> extends Function<T,R> { 091 092 /** 093 * Applies this function to the given argument, wrapping any checked exceptions in a {@link RuntimeException}. 094 * 095 * <p> 096 * This is the default implementation that makes this interface compatible with {@link Function}. 097 * It calls {@link #applyThrows(Object)} and wraps any checked exceptions. 098 * 099 * @param t The function argument. 100 * @return The function result. 101 * @throws RuntimeException if {@link #applyThrows(Object)} throws a checked exception. 102 */ 103 @Override 104 default R apply(T t) { 105 try { 106 return applyThrows(t); 107 } catch (Exception e) { 108 throw toRex(e); 109 } 110 } 111 112 /** 113 * Applies this function to the given argument, potentially throwing a checked exception. 114 * 115 * <p> 116 * This is the functional method that implementations must provide. It allows checked exceptions 117 * to be thrown directly, unlike the standard {@link Function#apply(Object)} method. 118 * 119 * <h5 class='section'>Example:</h5> 120 * <p class='bjava'> 121 * ThrowingFunction<String,Integer> <jv>parser</jv> = (<jv>s</jv>) -> { 122 * <jk>try</jk> { 123 * <jk>return</jk> Integer.parseInt(<jv>s</jv>); 124 * } <jk>catch</jk> (NumberFormatException <jv>e</jv>) { 125 * <jk>throw new</jk> ParseException(<js>"Invalid number: "</js> + <jv>s</jv>, 0); 126 * } 127 * }; 128 * 129 * <jk>try</jk> { 130 * <jk>int</jk> <jv>value</jv> = <jv>parser</jv>.applyThrows(<js>"123"</js>); 131 * } <jk>catch</jk> (ParseException <jv>e</jv>) { 132 * <jc>// Handle checked exception</jc> 133 * } 134 * </p> 135 * 136 * @param t The function argument. 137 * @return The function result. 138 * @throws Exception If an error occurs during function execution. 139 */ 140 R applyThrows(T t) throws Exception; 141}