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<String,Integer> <jv>printer</jv> = (<jv>name</jv>, <jv>age</jv>) -> 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<String,Integer> <jv>map</jv> = <jk>new</jk> HashMap<>(); 053 * Consumer2<String,Integer> <jv>putter</jv> = <jv>map</jv>::put; 054 * <jv>putter</jv>.apply(<js>"key"</js>, 42); 055 * 056 * <jc>// Operation composition</jc> 057 * Consumer2<String,Integer> <jv>log</jv> = (<jv>s</jv>, <jv>i</jv>) -> <jsm>logger</jsm>.info(<jv>s</jv> + <js>": "</js> + <jv>i</jv>); 058 * Consumer2<String,Integer> <jv>store</jv> = (<jv>s</jv>, <jv>i</jv>) -> <jv>cache</jv>.put(<jv>s</jv>, <jv>i</jv>); 059 * Consumer2<String,Integer> <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<String,Integer> <jv>validate</jv> = (<jv>s</jv>, <jv>i</jv>) -> { 087 * <jk>if</jk> (<jv>i</jv> < 0) <jk>throw new</jk> IllegalArgumentException(); 088 * }; 089 * Consumer2<String,Integer> <jv>process</jv> = (<jv>s</jv>, <jv>i</jv>) -> <jsm>process</jsm>(<jv>s</jv>, <jv>i</jv>); 090 * Consumer2<String,Integer> <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<String,Integer> <jv>handler</jv> = (<jv>key</jv>, <jv>value</jv>) -> { 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}