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.*;
020
021import java.util.function.*;
022
023/**
024 * A functional interface representing a function that accepts five arguments and produces a result.
025 *
026 * <p>
027 * This interface extends the standard Java {@link java.util.function.Function} pattern to support
028 * five-argument functions. It's useful when you need to pass functions with five parameters to methods
029 * that expect functional interfaces, such as in stream operations, builders, or callback patterns.
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>Composition support - provides {@link #andThen(Function)} for function chaining
035 *    <li>Type-safe - generic type parameters ensure compile-time type safety
036 * </ul>
037 *
038 * <h5 class='section'>Use Cases:</h5>
039 * <ul class='spaced-list'>
040 *    <li>Five-argument transformations in functional programming patterns
041 *    <li>Builder methods that accept five-parameter functions
042 *    <li>Stream operations requiring five-argument functions
043 *    <li>Callback patterns with five parameters
044 * </ul>
045 *
046 * <h5 class='section'>Usage:</h5>
047 * <p class='bjava'>
048 *    <jc>// Lambda expression</jc>
049 *    Function5&lt;String,Integer,Boolean,Double,Long,String&gt; <jv>format</jv> = (<jv>s</jv>, <jv>i</jv>, <jv>b</jv>, <jv>d</jv>, <jv>l</jv>) -&gt;
050 *       <jv>s</jv> + <js>"-"</js> + <jv>i</jv> + <js>"-"</js> + (<jv>b</jv> ? <js>"Y"</js> : <js>"N"</js>) + <js>"-"</js> + <jv>d</jv> + <js>"-"</js> + <jv>l</jv>;
051 *    String <jv>result</jv> = <jv>format</jv>.apply(<js>"prefix"</js>, 42, <jk>true</jk>, 95.5, 1234567890L);
052 *
053 *    <jc>// Function composition</jc>
054 *    Function5&lt;Integer,Integer,Integer,Integer,Integer,Integer&gt; <jv>add</jv> = (<jv>a</jv>, <jv>b</jv>, <jv>c</jv>, <jv>d</jv>, <jv>e</jv>) -&gt; <jv>a</jv> + <jv>b</jv> + <jv>c</jv> + <jv>d</jv> + <jv>e</jv>;
055 *    Function5&lt;Integer,Integer,Integer,Integer,Integer,String&gt; <jv>addAndFormat</jv> = <jv>add</jv>.andThen(Object::toString);
056 *    String <jv>sum</jv> = <jv>addAndFormat</jv>.apply(5, 3, 2, 1, 1);  <jc>// Returns "12"</jc>
057 * </p>
058 *
059 * <h5 class='section'>See Also:</h5><ul>
060 *    <li class='jc'>{@link Function2} - Two-argument function
061 *    <li class='jc'>{@link Function3} - Three-argument function
062 *    <li class='jc'>{@link Function4} - Four-argument function
063 *    <li class='link'><a class="doclink" href="https://juneau.apache.org/docs/topics/JuneauCommonsBasics">juneau-commons Basics</a>
064 * </ul>
065 *
066 * @param <A> The type of the first argument to the function.
067 * @param <B> The type of the second argument to the function.
068 * @param <C> The type of the third argument to the function.
069 * @param <D> The type of the fourth argument to the function.
070 * @param <E> The type of the fifth argument to the function.
071 * @param <R> The type of the result of the function.
072 */
073@FunctionalInterface
074public interface Function5<A,B,C,D,E,R> {
075
076   /**
077    * Returns a composed function that first applies this function to its input, and then applies
078    * the {@code after} function to the result.
079    *
080    * <p>
081    * This method enables function composition, allowing you to chain multiple transformations together.
082    *
083    * <h5 class='section'>Example:</h5>
084    * <p class='bjava'>
085    *    Function5&lt;Integer,Integer,Integer,Integer,Integer,Integer&gt; <jv>multiply</jv> = (<jv>a</jv>, <jv>b</jv>, <jv>c</jv>, <jv>d</jv>, <jv>e</jv>) -&gt; <jv>a</jv> * <jv>b</jv> * <jv>c</jv> * <jv>d</jv> * <jv>e</jv>;
086    *    Function5&lt;Integer,Integer,Integer,Integer,Integer,String&gt; <jv>multiplyAndFormat</jv> = <jv>multiply</jv>.andThen(<jv>n</jv> -&gt; <js>"Result: "</js> + <jv>n</jv>);
087    *    String <jv>result</jv> = <jv>multiplyAndFormat</jv>.apply(2, 2, 2, 2, 2);  <jc>// Returns "Result: 32"</jc>
088    * </p>
089    *
090    * @param <V> The type of output of the {@code after} function, and of the composed function.
091    * @param after The function to apply after this function is applied. Must not be <jk>null</jk>.
092    * @return A composed function that first applies this function and then applies the {@code after} function.
093    * @throws NullPointerException if {@code after} is <jk>null</jk>.
094    */
095   default <V> Function5<A,B,C,D,E,V> andThen(Function<? super R,? extends V> after) {
096      assertArgNotNull("after", after);
097      return (A a, B b, C c, D d, E e) -> after.apply(apply(a, b, c, d, e));
098   }
099
100   /**
101    * Applies this function to the given arguments.
102    *
103    * <h5 class='section'>Example:</h5>
104    * <p class='bjava'>
105    *    Function5&lt;String,Integer,Boolean,Double,Long,String&gt; <jv>format</jv> = (<jv>s</jv>, <jv>n</jv>, <jv>upper</jv>, <jv>mult</jv>, <jv>time</jv>) -&gt; {
106    *       String <jv>result</jv> = <jv>s</jv>.repeat(<jv>n</jv>);
107    *       <jv>result</jv> = <jv>upper</jv> ? <jv>result</jv>.toUpperCase() : <jv>result</jv>;
108    *       <jk>return</jk> <jv>result</jv> + <js>" x"</js> + <jv>mult</jv> + <js>" @"</js> + <jv>time</jv>;
109    *    };
110    *    String <jv>result</jv> = <jv>format</jv>.apply(<js>"ha"</js>, 2, <jk>true</jk>, 1.5, 1234567890L);
111    * </p>
112    *
113    * @param a The first function argument.
114    * @param b The second function argument.
115    * @param c The third function argument.
116    * @param d The fourth function argument.
117    * @param e The fifth function argument.
118    * @return The function result.
119    */
120   R apply(A a, B b, C c, D d, E e);
121}