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 a single value. 027 * 028 * <p> 029 * This class provides a simple wrapper for a single value that properly implements 030 * {@link #equals(Object)} and {@link #hashCode()} based on content rather than identity. 031 * This is particularly useful for HashMap keys when you want to use an array or need 032 * a wrapper that uses content-based equality. 033 * 034 * <h5 class='section'>Features:</h5> 035 * <ul class='spaced-list'> 036 * <li>Immutable - value 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 Tuple1 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>Using arrays as HashMap keys with proper content-based equality 052 * <li>Wrapping values that need content-based equality for collections 053 * <li>Creating composite keys from single values 054 * <li>Passing values through APIs that require object identity preservation 055 * </ul> 056 * 057 * <h5 class='section'>Usage:</h5> 058 * <p class='bjava'> 059 * <jc>// Using arrays as keys via Tuple1</jc> 060 * Map<Tuple1<String[]>,Integer> <jv>map</jv> = <jk>new</jk> HashMap<>(); 061 * <jv>map</jv>.put(Tuple1.<jsm>of</jsm>(<jk>new</jk> String[]{<js>"a"</js>,<js>"b"</js>}), 1); 062 * <jv>map</jv>.put(Tuple1.<jsm>of</jsm>(<jk>new</jk> String[]{<js>"a"</js>,<js>"b"</js>}), 2); <jc>// Replaces first entry</jc> 063 * System.<jsf>out</jsf>.println(<jv>map</jv>.size()); <jc>// Prints "1"</jc> 064 * 065 * <jc>// Using with other types</jc> 066 * Map<Tuple1<String>,Integer> <jv>stringMap</jv> = <jk>new</jk> HashMap<>(); 067 * <jv>stringMap</jv>.put(Tuple1.<jsm>of</jsm>(<js>"key"</js>), 42); 068 * Integer <jv>value</jv> = <jv>stringMap</jv>.get(Tuple1.<jsm>of</jsm>(<js>"key"</js>)); <jc>// Returns 42</jc> 069 * </p> 070 * 071 * <h5 class='section'>Thread Safety:</h5> 072 * <p> 073 * This class is immutable and therefore thread-safe. Multiple threads can safely access a Tuple1 instance 074 * concurrently without synchronization. 075 * 076 * <h5 class='section'>See Also:</h5><ul> 077 * <li class='jc'>{@link Tuple2} - Two-value tuple 078 * <li class='jc'>{@link Tuple3} - Three-value tuple 079 * <li class='jc'>{@link Tuple4} - Four-value tuple 080 * <li class='jc'>{@link Tuple5} - Five-value tuple 081 * <li class='link'><a class="doclink" href="https://juneau.apache.org/docs/topics/JuneauCommonsBasics">juneau-commons Basics</a> 082 * </ul> 083 * 084 * @param <A> The type of the value in this tuple. 085 */ 086public class Tuple1<A> { 087 088 /** 089 * Creates a new tuple containing the specified value. 090 * 091 * <h5 class='section'>Example:</h5> 092 * <p class='bjava'> 093 * Tuple1<String> <jv>tuple</jv> = Tuple1.<jsm>of</jsm>(<js>"value"</js>); 094 * Tuple1<String[]> <jv>arrayTuple</jv> = Tuple1.<jsm>of</jsm>(<jk>new</jk> String[]{<js>"a"</js>, <js>"b"</js>}); 095 * </p> 096 * 097 * @param <A> The value type. 098 * @param a The value to wrap in the tuple. 099 * @return A new tuple containing the specified value. 100 */ 101 public static <A> Tuple1<A> of(A a) { 102 return new Tuple1<>(a); 103 } 104 105 private final A a; 106 private final int hashCode; 107 108 /** 109 * Constructor. 110 * 111 * @param a Object value. 112 */ 113 public Tuple1(A a) { 114 this.a = a; 115 this.hashCode = h(a); 116 } 117 118 @Override /* Overridden from Object */ 119 public boolean equals(Object o) { 120 return o instanceof Tuple1<?> o2 && eq(this, o2, (x, y) -> eq(x.a, y.a)); 121 } 122 123 /** 124 * Returns the value contained in this tuple. 125 * 126 * <h5 class='section'>Example:</h5> 127 * <p class='bjava'> 128 * Tuple1<String> <jv>tuple</jv> = Tuple1.<jsm>of</jsm>(<js>"hello"</js>); 129 * String <jv>value</jv> = <jv>tuple</jv>.getA(); <jc>// Returns "hello"</jc> 130 * </p> 131 * 132 * @return The value contained in this tuple. 133 */ 134 public A getA() { return a; } 135 136 /** 137 * Returns the value contained in this tuple wrapped in an {@link Optional}. 138 * 139 * <h5 class='section'>Example:</h5> 140 * <p class='bjava'> 141 * Tuple1<String> <jv>tuple</jv> = Tuple1.<jsm>of</jsm>(<js>"hello"</js>); 142 * Optional<String> <jv>value</jv> = <jv>tuple</jv>.optA(); <jc>// Returns Optional.of("hello")</jc> 143 * 144 * Tuple1<String> <jv>tuple2</jv> = Tuple1.<jsm>of</jsm>(<jk>null</jk>); 145 * Optional<String> <jv>value2</jv> = <jv>tuple2</jv>.optA(); <jc>// Returns Optional.empty()</jc> 146 * </p> 147 * 148 * @return The value wrapped in an Optional, or Optional.empty() if the value is null. 149 */ 150 public Optional<A> optA() { 151 return Optional.ofNullable(a); 152 } 153 154 @Override /* Overridden from Object */ 155 public int hashCode() { 156 return hashCode; 157 } 158}