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