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.Objects;
21
22 import org.apache.commons.lang3.builder.CompareToBuilder;
23
24 /**
25 * A triple consisting of three elements.
26 *
27 * <p>
28 * This class is an abstract implementation defining the basic API.
29 * It refers to the elements as 'left', 'middle' and 'right'.
30 * </p>
31 *
32 * <p>
33 * Subclass implementations may be mutable or immutable.
34 * However, there is no restriction on the type of the stored objects that may be stored.
35 * If mutable objects are stored in the triple, then the triple itself effectively becomes mutable.
36 * </p>
37 *
38 * @param <L> The left element type.
39 * @param <M> The middle element type.
40 * @param <R> The right element type.
41 * @since 3.2
42 */
43 public abstract class Triple<L, M, R> implements Comparable<Triple<L, M, R>>, Serializable {
44
45 /** Serialization version */
46 private static final long serialVersionUID = 1L;
47
48 /**
49 * An empty array.
50 * <p>
51 * Consider using {@link #emptyArray()} to avoid generics warnings.
52 * </p>
53 *
54 * @since 3.10
55 */
56 public static final Triple<?, ?, ?>[] EMPTY_ARRAY = {};
57
58 /**
59 * Returns the empty array singleton that can be assigned without compiler warning.
60 *
61 * @param <L> The left element type.
62 * @param <M> The middle element type.
63 * @param <R> The right element type.
64 * @return The empty array singleton that can be assigned without compiler warning.
65 * @since 3.10
66 */
67 @SuppressWarnings("unchecked")
68 public static <L, M, R> Triple<L, M, R>[] emptyArray() {
69 return (Triple<L, M, R>[]) EMPTY_ARRAY;
70 }
71
72 /**
73 * Obtains an immutable triple of three objects inferring the generic types.
74 *
75 * @param <L> The left element type.
76 * @param <M> The middle element type.
77 * @param <R> The right element type.
78 * @param left The left element, may be null.
79 * @param middle The middle element, may be null.
80 * @param right The right element, may be null.
81 * @return An immutable triple formed from the three parameters, not null.
82 */
83 public static <L, M, R> Triple<L, M, R> of(final L left, final M middle, final R right) {
84 return ImmutableTriple.of(left, middle, right);
85 }
86
87 /**
88 * Obtains an immutable triple of three non-null objects inferring the generic types.
89 *
90 * @param <L> The left element type.
91 * @param <M> The middle element type.
92 * @param <R> The right element type.
93 * @param left The left element, may not be null.
94 * @param middle The middle element, may not be null.
95 * @param right The right element, may not be null.
96 * @return An immutable triple formed from the three parameters, not null.
97 * @throws NullPointerException Thrown if any input is null.
98 * @since 3.13.0
99 */
100 public static <L, M, R> Triple<L, M, R> ofNonNull(final L left, final M middle, final R right) {
101 return ImmutableTriple.ofNonNull(left, middle, right);
102 }
103
104 /**
105 * Constructs a new instance.
106 */
107 public Triple() {
108 // empty
109 }
110
111 /**
112 * Compares the triple based on the left element, followed by the middle element,
113 * finally the right element.
114 * The types must be {@link Comparable}.
115 *
116 * @param other The other triple, not null.
117 * @return negative if this is less, zero if equal, positive if greater.
118 */
119 @Override
120 public int compareTo(final Triple<L, M, R> other) {
121 return new CompareToBuilder().append(getLeft(), other.getLeft())
122 .append(getMiddle(), other.getMiddle())
123 .append(getRight(), other.getRight()).toComparison();
124 }
125
126 /**
127 * Compares this triple to another based on the three elements.
128 *
129 * @param obj The object to compare to, null returns false.
130 * @return true if the elements of the triple are equal.
131 */
132 @Override
133 public boolean equals(final Object obj) {
134 if (obj == this) {
135 return true;
136 }
137 if (obj instanceof Triple<?, ?, ?>) {
138 final Triple<?, ?, ?> other = (Triple<?, ?, ?>) obj;
139 return Objects.equals(getLeft(), other.getLeft())
140 && Objects.equals(getMiddle(), other.getMiddle())
141 && Objects.equals(getRight(), other.getRight());
142 }
143 return false;
144 }
145
146 /**
147 * Gets the left element from this triple.
148 *
149 * @return The left element, may be null.
150 */
151 public abstract L getLeft();
152
153 /**
154 * Gets the middle element from this triple.
155 *
156 * @return The middle element, may be null.
157 */
158 public abstract M getMiddle();
159
160 /**
161 * Gets the right element from this triple.
162 *
163 * @return The right element, may be null.
164 */
165 public abstract R getRight();
166
167 /**
168 * Returns a suitable hash code.
169 * <p>
170 * The hash code is adapted from the definition in {@code Map.Entry}.
171 * </p>
172 *
173 * @return The hash code.
174 */
175 @Override
176 public int hashCode() {
177 // See Map.Entry API specification
178 return Objects.hashCode(getLeft()) ^ Objects.hashCode(getMiddle()) ^ Objects.hashCode(getRight());
179 }
180
181 /**
182 * Returns a String representation of this triple using the format {@code (left,middle,right)}.
183 *
184 * @return A string describing this object, not null.
185 */
186 @Override
187 public String toString() {
188 return "(" + getLeft() + "," + getMiddle() + "," + getRight() + ")";
189 }
190
191 /**
192 * Formats the receiver using the given format.
193 *
194 * <p>
195 * This uses {@link java.util.Formattable} to perform the formatting. Three variables may
196 * be used to embed the left and right elements. Use {@code %1$s} for the left
197 * element, {@code %2$s} for the middle and {@code %3$s} for the right element.
198 * The default format used by {@code toString()} is {@code (%1$s,%2$s,%3$s)}.
199 * </p>
200 *
201 * @param format The format string, optionally containing {@code %1$s}, {@code %2$s} and {@code %3$s}, not null.
202 * @return The formatted string, not null.
203 */
204 public String toString(final String format) {
205 return String.format(format, getLeft(), getMiddle(), getRight());
206 }
207
208 }
209