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
021/**
022 * A functional interface representing an operation that accepts two arguments and returns no result.
023 *
024 * <p>
025 * This interface extends the standard Java {@link java.util.function.Consumer} pattern to support
026 * two-argument consumers. It's useful when you need to pass operations with two parameters to methods
027 * that expect functional interfaces, such as in iteration, builders, or callback patterns.
028 *
029 * <h5 class='section'>Features:</h5>
030 * <ul class='spaced-list'>
031 *    <li>Functional interface - can be used with lambda expressions and method references
032 *    <li>Composition support - provides {@link #andThen(Consumer2)} for operation chaining
033 *    <li>Side-effect operations - designed for operations that perform side effects rather than return values
034 * </ul>
035 *
036 * <h5 class='section'>Use Cases:</h5>
037 * <ul class='spaced-list'>
038 *    <li>Two-argument operations in iteration patterns
039 *    <li>Builder methods that accept two-parameter operations
040 *    <li>Callback patterns with two parameters
041 *    <li>Event handlers that process two values
042 * </ul>
043 *
044 * <h5 class='section'>Usage:</h5>
045 * <p class='bjava'>
046 *    <jc>// Lambda expression</jc>
047 *    Consumer2&lt;String,Integer&gt; <jv>printer</jv> = (<jv>name</jv>, <jv>age</jv>) -&gt;
048 *       System.<jsf>out</jsf>.println(<jv>name</jv> + <js>" is "</js> + <jv>age</jv> + <js>" years old"</js>);
049 *    <jv>printer</jv>.apply(<js>"Alice"</js>, 30);  <jc>// Prints "Alice is 30 years old"</jc>
050 *
051 *    <jc>// Method reference</jc>
052 *    Map&lt;String,Integer&gt; <jv>map</jv> = <jk>new</jk> HashMap&lt;&gt;();
053 *    Consumer2&lt;String,Integer&gt; <jv>putter</jv> = <jv>map</jv>::put;
054 *    <jv>putter</jv>.apply(<js>"key"</js>, 42);
055 *
056    *    <jc>// Operation composition</jc>
057 *    Consumer2&lt;String,Integer&gt; <jv>log</jv> = (<jv>s</jv>, <jv>i</jv>) -&gt; <jsm>logger</jsm>.info(<jv>s</jv> + <js>": "</js> + <jv>i</jv>);
058 *    Consumer2&lt;String,Integer&gt; <jv>store</jv> = (<jv>s</jv>, <jv>i</jv>) -&gt; <jv>cache</jv>.put(<jv>s</jv>, <jv>i</jv>);
059 *    Consumer2&lt;String,Integer&gt; <jv>logAndStore</jv> = <jv>log</jv>.andThen(<jv>store</jv>);
060 *    <jv>logAndStore</jv>.apply(<js>"data"</js>, 100);  <jc>// Logs and stores</jc>
061 * </p>
062 *
063 * <h5 class='section'>See Also:</h5><ul>
064 *    <li class='jc'>{@link Consumer3} - Three-argument consumer
065 *    <li class='jc'>{@link Consumer4} - Four-argument consumer
066 *    <li class='jc'>{@link Consumer5} - Five-argument consumer
067 *    <li class='link'><a class="doclink" href="https://juneau.apache.org/docs/topics/JuneauCommonsBasics">juneau-commons Basics</a>
068 * </ul>
069 *
070 * @param <A> The type of the first argument to the operation.
071 * @param <B> The type of the second argument to the operation.
072 */
073@FunctionalInterface
074public interface Consumer2<A,B> {
075
076   /**
077    * Returns a composed {@link Consumer2} that performs, in sequence, this operation followed by the {@code after} operation.
078    *
079    * <p>
080    * This method enables operation composition, allowing you to chain multiple operations together.
081    * If performing either operation throws an exception, it is relayed to the caller of the composed operation.
082    * If performing this operation throws an exception, the {@code after} operation will not be performed.
083    *
084    * <h5 class='section'>Example:</h5>
085    * <p class='bjava'>
086    *    Consumer2&lt;String,Integer&gt; <jv>validate</jv> = (<jv>s</jv>, <jv>i</jv>) -&gt; {
087    *       <jk>if</jk> (<jv>i</jv> &lt; 0) <jk>throw new</jk> IllegalArgumentException();
088    *    };
089    *    Consumer2&lt;String,Integer&gt; <jv>process</jv> = (<jv>s</jv>, <jv>i</jv>) -&gt; <jsm>process</jsm>(<jv>s</jv>, <jv>i</jv>);
090    *    Consumer2&lt;String,Integer&gt; <jv>validateAndProcess</jv> = <jv>validate</jv>.andThen(<jv>process</jv>);
091    *    <jv>validateAndProcess</jv>.apply(<js>"data"</js>, 42);  <jc>// Validates then processes</jc>
092    * </p>
093    *
094    * @param after The operation to perform after this operation. Must not be <jk>null</jk>.
095    * @return A composed {@link Consumer2} that performs in sequence this operation followed by the {@code after} operation.
096    * @throws NullPointerException if {@code after} is <jk>null</jk>.
097    */
098   default Consumer2<A,B> andThen(Consumer2<? super A,? super B> after) {  // NOSONAR - false positive on generics
099      assertArgNotNull("after", after);
100      return (A a, B b) -> {
101         apply(a, b);
102         after.apply(a, b);
103      };
104   }
105
106   /**
107    * Performs this operation on the given arguments.
108    *
109    * <h5 class='section'>Example:</h5>
110    * <p class='bjava'>
111    *    Consumer2&lt;String,Integer&gt; <jv>handler</jv> = (<jv>key</jv>, <jv>value</jv>) -&gt; {
112    *       <jv>map</jv>.put(<jv>key</jv>, <jv>value</jv>);
113    *       <jv>cache</jv>.invalidate(<jv>key</jv>);
114    *    };
115    *    <jv>handler</jv>.apply(<js>"user"</js>, 12345);
116    * </p>
117    *
118    * @param a The first operation argument.
119    * @param b The second operation argument.
120    */
121   void apply(A a, B b);
122}