1 /*
2 * Licensed to the Apache Software Foundation (ASF) under one or more
3 * contributor license agreements. See the NOTICE file distributed with
4 * this work for additional information regarding copyright ownership.
5 * The ASF licenses this file to You under the Apache License, Version 2.0
6 * (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
8 *
9 * https://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17 package org.apache.commons.lang3.tuple;
18
19 import java.io.Serializable;
20 import java.util.Map;
21 import java.util.Objects;
22
23 import org.apache.commons.lang3.builder.CompareToBuilder;
24 import org.apache.commons.lang3.function.FailableBiConsumer;
25 import org.apache.commons.lang3.function.FailableBiFunction;
26
27 /**
28 * A pair consisting of two elements.
29 *
30 * <p>
31 * This class is an abstract implementation defining the basic API.
32 * It refers to the elements as 'left' and 'right'. It also implements the
33 * {@code Map.Entry} interface where the key is 'left' and the value is 'right'.
34 * </p>
35 *
36 * <p>
37 * Subclass implementations may be mutable or immutable.
38 * However, there is no restriction on the type of the stored objects that may be stored.
39 * If mutable objects are stored in the pair, then the pair itself effectively becomes mutable.
40 * </p>
41 *
42 * @param <L> The left element type.
43 * @param <R> The right element type.
44 * @since 3.0
45 */
46 public abstract class Pair<L, R> implements Map.Entry<L, R>, Comparable<Pair<L, R>>, Serializable {
47
48 /** Serialization version */
49 private static final long serialVersionUID = 4954918890077093841L;
50
51 /**
52 * An empty array.
53 * <p>
54 * Consider using {@link #emptyArray()} to avoid generics warnings.
55 * </p>
56 *
57 * @since 3.10
58 */
59 public static final Pair<?, ?>[] EMPTY_ARRAY = {};
60
61 /**
62 * Returns the empty array singleton that can be assigned without compiler warning.
63 *
64 * @param <L> The left element type.
65 * @param <R> The right element type.
66 * @return The empty array singleton that can be assigned without compiler warning.
67 * @since 3.10
68 */
69 @SuppressWarnings("unchecked")
70 public static <L, R> Pair<L, R>[] emptyArray() {
71 return (Pair<L, R>[]) EMPTY_ARRAY;
72 }
73
74 /**
75 * Creates an immutable pair of two objects inferring the generic types.
76 *
77 * @param <L> The left element type.
78 * @param <R> The right element type.
79 * @param left The left element, may be null.
80 * @param right The right element, may be null.
81 * @return An immutable pair formed from the two parameters, not null.
82 */
83 public static <L, R> Pair<L, R> of(final L left, final R right) {
84 return ImmutablePair.of(left, right);
85 }
86
87 /**
88 * Creates an immutable pair from a map entry.
89 *
90 * @param <L> The left element type.
91 * @param <R> The right element type.
92 * @param pair The map entry.
93 * @return An immutable pair formed from the map entry.
94 * @since 3.10
95 */
96 public static <L, R> Pair<L, R> of(final Map.Entry<L, R> pair) {
97 return ImmutablePair.of(pair);
98 }
99
100 /**
101 * Creates an immutable pair of two non-null objects inferring the generic types.
102 *
103 * @param <L> The left element type.
104 * @param <R> The right element type.
105 * @param left The left element, may not be null.
106 * @param right The right element, may not be null.
107 * @return An immutable pair formed from the two parameters, not null.
108 * @throws NullPointerException Thrown if any input is null.
109 * @since 3.13.0
110 */
111 public static <L, R> Pair<L, R> ofNonNull(final L left, final R right) {
112 return ImmutablePair.ofNonNull(left, right);
113 }
114
115 /**
116 * Constructs a new instance.
117 */
118 public Pair() {
119 // empty
120 }
121
122 /**
123 * Accepts this key and value as arguments to the given consumer.
124 *
125 * @param <E> The kind of thrown exception or error.
126 * @param consumer The consumer to call.
127 * @throws E Thrown when the consumer fails.
128 * @since 3.13.0
129 */
130 public <E extends Throwable> void accept(final FailableBiConsumer<L, R, E> consumer) throws E {
131 consumer.accept(getKey(), getValue());
132 }
133
134 /**
135 * Applies this key and value as arguments to the given function.
136 *
137 * @param <V> The function return type.
138 * @param <E> The kind of thrown exception or error.
139 * @param function The consumer to call.
140 * @return The function's return value.
141 * @throws E Thrown when the consumer fails.
142 * @since 3.13.0
143 */
144 public <V, E extends Throwable> V apply(final FailableBiFunction<L, R, V, E> function) throws E {
145 return function.apply(getKey(), getValue());
146 }
147
148 /**
149 * Compares the pair based on the left element followed by the right element.
150 * The types must be {@link Comparable}.
151 *
152 * @param other The other pair, not null.
153 * @return negative if this is less, zero if equal, positive if greater.
154 */
155 @Override
156 public int compareTo(final Pair<L, R> other) {
157 // @formatter:off
158 return new CompareToBuilder()
159 .append(getLeft(), other.getLeft())
160 .append(getRight(), other.getRight())
161 .toComparison();
162 // @formatter:on
163 }
164
165 /**
166 * Compares this pair to another based on the two elements.
167 *
168 * @param obj The object to compare to, null returns false.
169 * @return true if the elements of the pair are equal.
170 */
171 @Override
172 public boolean equals(final Object obj) {
173 if (obj == this) {
174 return true;
175 }
176 if (obj instanceof Map.Entry<?, ?>) {
177 final Map.Entry<?, ?> other = (Map.Entry<?, ?>) obj;
178 return Objects.equals(getKey(), other.getKey())
179 && Objects.equals(getValue(), other.getValue());
180 }
181 return false;
182 }
183
184 /**
185 * Gets the key from this pair.
186 *
187 * <p>
188 * This method implements the {@code Map.Entry} interface returning the
189 * left element as the key.
190 * </p>
191 *
192 * @return The left element as the key, may be null.
193 */
194 @Override
195 public final L getKey() {
196 return getLeft();
197 }
198
199 /**
200 * Gets the left element from this pair.
201 *
202 * <p>
203 * When treated as a key-value pair, this is the key.
204 * </p>
205 *
206 * @return The left element, may be null.
207 */
208 public abstract L getLeft();
209
210 /**
211 * Gets the right element from this pair.
212 *
213 * <p>
214 * When treated as a key-value pair, this is the value.
215 * </p>
216 *
217 * @return The right element, may be null.
218 */
219 public abstract R getRight();
220
221 /**
222 * Gets the value from this pair.
223 *
224 * <p>
225 * This method implements the {@code Map.Entry} interface returning the
226 * right element as the value.
227 * </p>
228 *
229 * @return The right element as the value, may be null.
230 */
231 @Override
232 public R getValue() {
233 return getRight();
234 }
235
236 /**
237 * Returns a suitable hash code.
238 * <p>
239 * The hash code follows the definition in {@code Map.Entry}.
240 * </p>
241 *
242 * @return The hash code.
243 */
244 @Override
245 public int hashCode() {
246 // See Map.Entry API specification
247 return Objects.hashCode(getKey()) ^ Objects.hashCode(getValue());
248 }
249
250 /**
251 * Returns a String representation of this pair using the format {@code (left,right)}.
252 *
253 * @return A string describing this object, not null.
254 */
255 @Override
256 public String toString() {
257 return "(" + getLeft() + ',' + getRight() + ')';
258 }
259
260 /**
261 * Formats the receiver using the given format.
262 *
263 * <p>
264 * This uses {@link String#format(String, Object...)} to the format. Two variables may be used to embed the left and right elements. Use {@code %1$s} for
265 * the left element (key) and {@code %2$s} for the right element (value).
266 * </p>
267 *
268 * @param format The format string, optionally containing {@code %1$s} and {@code %2$s}, not null.
269 * @return The formatted string, not null.
270 * @see String#format(String, Object...)
271 */
272 public String toString(final String format) {
273 return String.format(format, getLeft(), getRight());
274 }
275
276 }