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.Utils.*;
020
021import java.util.Optional;
022
023import org.apache.juneau.commons.lang.*;
024
025/**
026 * Represents an immutable tuple containing two values.
027 *
028 * <p>
029 * This class provides a simple wrapper for two values that properly implements
030 * {@link #equals(Object)} and {@link #hashCode()} based on content rather than identity.
031 * This is particularly useful for HashMap composite keys when you need to combine multiple
032 * values into a single key.
033 *
034 * <h5 class='section'>Features:</h5>
035 * <ul class='spaced-list'>
036 *    <li>Immutable - values cannot be changed after construction
037 *    <li>Content-based equality - uses {@link org.apache.juneau.commons.utils.Utils#eq(Object, Object)} for comparison
038 *    <li>Content-based hashing - uses {@link HashCode#of(Object...)} for hash code computation
039 *    <li>Array support - properly handles arrays with content-based equality and hashing
040 * </ul>
041 *
042 * <h5 class='section'>Array Support:</h5>
043 * <p>
044 * Unlike using arrays directly as HashMap keys (which use identity-based equality), this class properly
045 * handles arrays by using content-based equality and hashing via {@link HashCode#of(Object...)} which
046 * internally uses {@link java.util.Arrays#hashCode(Object[])} for arrays. This means two Tuple2 instances
047 * containing arrays with the same content will be considered equal.
048 *
049 * <h5 class='section'>Use Cases:</h5>
050 * <ul class='spaced-list'>
051 *    <li>Composite keys for HashMap lookups (e.g., combining two identifiers)
052 *    <li>Using arrays in composite keys with proper content-based equality
053 *    <li>Returning multiple values from methods (alternative to creating a custom class)
054 *    <li>Grouping related values together for processing
055 * </ul>
056 *
057 * <h5 class='section'>Usage:</h5>
058 * <p class='bjava'>
059 *    <jc>// Using arrays in composite keys</jc>
060 *    Map&lt;Tuple2&lt;String,int[]&gt;,Result&gt; <jv>map</jv> = <jk>new</jk> HashMap&lt;&gt;();
061 *    <jv>map</jv>.put(Tuple2.<jsm>of</jsm>(<js>"key"</js>, <jk>new</jk> <jk>int</jk>[]{1,2,3}), <jv>result1</jv>);
062 *    Result <jv>r</jv> = <jv>map</jv>.get(Tuple2.<jsm>of</jsm>(<js>"key"</js>, <jk>new</jk> <jk>int</jk>[]{1,2,3}));  <jc>// Works correctly!</jc>
063 *
064 *    <jc>// Simple composite key</jc>
065 *    Map&lt;Tuple2&lt;String,Integer&gt;,String&gt; <jv>cache</jv> = <jk>new</jk> HashMap&lt;&gt;();
066 *    <jv>cache</jv>.put(Tuple2.<jsm>of</jsm>(<js>"user"</js>, 12345), <js>"John Doe"</js>);
067 *    String <jv>name</jv> = <jv>cache</jv>.get(Tuple2.<jsm>of</jsm>(<js>"user"</js>, 12345));  <jc>// Returns "John Doe"</jc>
068 * </p>
069 *
070 * <h5 class='section'>Thread Safety:</h5>
071 * <p>
072 * This class is immutable and therefore thread-safe. Multiple threads can safely access a Tuple2 instance
073 * concurrently without synchronization.
074 *
075 * <h5 class='section'>See Also:</h5><ul>
076 *    <li class='jc'>{@link Tuple1} - Single-value tuple
077 *    <li class='jc'>{@link Tuple3} - Three-value tuple
078 *    <li class='jc'>{@link Tuple4} - Four-value tuple
079 *    <li class='jc'>{@link Tuple5} - Five-value tuple
080 *    <li class='link'><a class="doclink" href="https://juneau.apache.org/docs/topics/JuneauCommonsBasics">juneau-commons Basics</a>
081 * </ul>
082 *
083 * @param <A> The type of the first value in this tuple.
084 * @param <B> The type of the second value in this tuple.
085 */
086public class Tuple2<A,B> {
087
088   /**
089    * Creates a new tuple containing the specified two values.
090    *
091    * <h5 class='section'>Example:</h5>
092    * <p class='bjava'>
093    *    Tuple2&lt;String,Integer&gt; <jv>tuple</jv> = Tuple2.<jsm>of</jsm>(<js>"name"</js>, 42);
094    *    Tuple2&lt;String[],int[]&gt; <jv>arrayTuple</jv> = Tuple2.<jsm>of</jsm>(
095    *       <jk>new</jk> String[]{<js>"a"</js>, <js>"b"</js>},
096    *       <jk>new</jk> <jk>int</jk>[]{1, 2}
097    *    );
098    * </p>
099    *
100    * @param <A> The type of the first value.
101    * @param <B> The type of the second value.
102    * @param a The first value.
103    * @param b The second value.
104    * @return A new tuple containing the specified values.
105    */
106   public static <A,B> Tuple2<A,B> of(A a, B b) {
107      return new Tuple2<>(a, b);
108   }
109
110   private final A a;
111   private final B b;
112   private final int hashCode;
113
114   /**
115    * Constructor.
116    *
117    * @param a Object 1.
118    * @param b Object 2.
119    */
120   public Tuple2(A a, B b) {
121      this.a = a;
122      this.b = b;
123      this.hashCode = h(a, b);
124   }
125
126   @Override /* Overridden from Object */
127   public boolean equals(Object o) {
128      return o instanceof Tuple2<?,?> o2 && eq(this, o2, (x, y) -> eq(x.a, y.a) && eq(x.b, y.b));
129   }
130
131   /**
132    * Returns the first value in this tuple.
133    *
134    * <h5 class='section'>Example:</h5>
135    * <p class='bjava'>
136    *    Tuple2&lt;String,Integer&gt; <jv>tuple</jv> = Tuple2.<jsm>of</jsm>(<js>"hello"</js>, 42);
137    *    String <jv>first</jv> = <jv>tuple</jv>.getA();  <jc>// Returns "hello"</jc>
138    * </p>
139    *
140    * @return The first value in this tuple.
141    */
142   public A getA() { return a; }
143
144   /**
145    * Returns the second value in this tuple.
146    *
147    * <h5 class='section'>Example:</h5>
148    * <p class='bjava'>
149    *    Tuple2&lt;String,Integer&gt; <jv>tuple</jv> = Tuple2.<jsm>of</jsm>(<js>"hello"</js>, 42);
150    *    Integer <jv>second</jv> = <jv>tuple</jv>.getB();  <jc>// Returns 42</jc>
151    * </p>
152    *
153    * @return The second value in this tuple.
154    */
155   public B getB() { return b; }
156
157   /**
158    * Returns the first value in this tuple wrapped in an {@link Optional}.
159    *
160    * <h5 class='section'>Example:</h5>
161    * <p class='bjava'>
162    *    Tuple2&lt;String,Integer&gt; <jv>tuple</jv> = Tuple2.<jsm>of</jsm>(<js>"hello"</js>, 42);
163    *    Optional&lt;String&gt; <jv>first</jv> = <jv>tuple</jv>.optA();  <jc>// Returns Optional.of("hello")</jc>
164    *
165    *    Tuple2&lt;String,Integer&gt; <jv>tuple2</jv> = Tuple2.<jsm>of</jsm>(<jk>null</jk>, 42);
166    *    Optional&lt;String&gt; <jv>first2</jv> = <jv>tuple2</jv>.optA();  <jc>// Returns Optional.empty()</jc>
167    * </p>
168    *
169    * @return The first value wrapped in an Optional, or Optional.empty() if the value is null.
170    */
171   public Optional<A> optA() {
172      return Optional.ofNullable(a);
173   }
174
175   /**
176    * Returns the second value in this tuple wrapped in an {@link Optional}.
177    *
178    * <h5 class='section'>Example:</h5>
179    * <p class='bjava'>
180    *    Tuple2&lt;String,Integer&gt; <jv>tuple</jv> = Tuple2.<jsm>of</jsm>(<js>"hello"</js>, 42);
181    *    Optional&lt;Integer&gt; <jv>second</jv> = <jv>tuple</jv>.optB();  <jc>// Returns Optional.of(42)</jc>
182    *
183    *    Tuple2&lt;String,Integer&gt; <jv>tuple2</jv> = Tuple2.<jsm>of</jsm>(<js>"hello"</js>, <jk>null</jk>);
184    *    Optional&lt;Integer&gt; <jv>second2</jv> = <jv>tuple2</jv>.optB();  <jc>// Returns Optional.empty()</jc>
185    * </p>
186    *
187    * @return The second value wrapped in an Optional, or Optional.empty() if the value is null.
188    */
189   public Optional<B> optB() {
190      return Optional.ofNullable(b);
191   }
192
193   @Override /* Overridden from Object */
194   public int hashCode() {
195      return hashCode;
196   }
197}