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.commons.lang3.tuple;
018
019import java.io.Serializable;
020import java.util.Map;
021import java.util.Objects;
022
023import org.apache.commons.lang3.builder.CompareToBuilder;
024
025/**
026 * <p>A pair consisting of two elements.</p>
027 *
028 * <p>This class is an abstract implementation defining the basic API.
029 * It refers to the elements as 'left' and 'right'. It also implements the
030 * {@code Map.Entry} interface where the key is 'left' and the value is 'right'.</p>
031 *
032 * <p>Subclass implementations may be mutable or immutable.
033 * However, there is no restriction on the type of the stored objects that may be stored.
034 * If mutable objects are stored in the pair, then the pair itself effectively becomes mutable.</p>
035 *
036 * @param <L> the left element type
037 * @param <R> the right element type
038 *
039 * @since 3.0
040 */
041public abstract class Pair<L, R> implements Map.Entry<L, R>, Comparable<Pair<L, R>>, Serializable {
042
043    private static final class PairAdapter<L, R> extends Pair<L, R> {
044
045        private static final long serialVersionUID = 1L;
046
047        @Override
048        public L getLeft() {
049            return null;
050        }
051
052        @Override
053        public R getRight() {
054            return null;
055        }
056
057        @Override
058        public R setValue(final R value) {
059            return null;
060        }
061
062    }
063
064    /** Serialization version */
065    private static final long serialVersionUID = 4954918890077093841L;
066
067    /**
068     * An empty array.
069     * <p>
070     * Consider using {@link #emptyArray()} to avoid generics warnings.
071     * </p>
072     *
073     * @since 3.10.
074     */
075    public static final Pair<?, ?>[] EMPTY_ARRAY = new PairAdapter[0];
076
077    /**
078     * Returns the empty array singleton that can be assigned without compiler warning.
079     *
080     * @param <L> the left element type
081     * @param <R> the right element type
082     * @return the empty array singleton that can be assigned without compiler warning.
083     *
084     * @since 3.10.
085     */
086    @SuppressWarnings("unchecked")
087    public static <L, R> Pair<L, R>[] emptyArray() {
088        return (Pair<L, R>[]) EMPTY_ARRAY;
089    }
090
091    /**
092     * <p>Creates an immutable pair of two objects inferring the generic types.</p>
093     *
094     * <p>This factory allows the pair to be created using inference to
095     * obtain the generic types.</p>
096     *
097     * @param <L> the left element type
098     * @param <R> the right element type
099     * @param left  the left element, may be null
100     * @param right  the right element, may be null
101     * @return a pair formed from the two parameters, not null
102     */
103    public static <L, R> Pair<L, R> of(final L left, final R right) {
104        return ImmutablePair.of(left, right);
105    }
106
107    /**
108     * <p>Creates an immutable pair from an existing pair.</p>
109     *
110     * <p>This factory allows the pair to be created using inference to
111     * obtain the generic types.</p>
112     *
113     * @param <L> the left element type
114     * @param <R> the right element type
115     * @param pair the existing pair.
116     * @return a pair formed from the two parameters, not null
117     * @since 3.10
118     */
119    public static <L, R> Pair<L, R> of(final Map.Entry<L, R> pair) {
120        return ImmutablePair.of(pair);
121    }
122
123    //-----------------------------------------------------------------------
124    /**
125     * <p>Compares the pair based on the left element followed by the right element.
126     * The types must be {@code Comparable}.</p>
127     *
128     * @param other  the other pair, not null
129     * @return negative if this is less, zero if equal, positive if greater
130     */
131    @Override
132    public int compareTo(final Pair<L, R> other) {
133      return new CompareToBuilder().append(getLeft(), other.getLeft())
134              .append(getRight(), other.getRight()).toComparison();
135    }
136
137    /**
138     * <p>Compares this pair to another based on the two elements.</p>
139     *
140     * @param obj  the object to compare to, null returns false
141     * @return true if the elements of the pair are equal
142     */
143    @Override
144    public boolean equals(final Object obj) {
145        if (obj == this) {
146            return true;
147        }
148        if (obj instanceof Map.Entry<?, ?>) {
149            final Map.Entry<?, ?> other = (Map.Entry<?, ?>) obj;
150            return Objects.equals(getKey(), other.getKey())
151                    && Objects.equals(getValue(), other.getValue());
152        }
153        return false;
154    }
155
156    /**
157     * <p>Gets the key from this pair.</p>
158     *
159     * <p>This method implements the {@code Map.Entry} interface returning the
160     * left element as the key.</p>
161     *
162     * @return the left element as the key, may be null
163     */
164    @Override
165    public final L getKey() {
166        return getLeft();
167    }
168
169    //-----------------------------------------------------------------------
170    /**
171     * <p>Gets the left element from this pair.</p>
172     *
173     * <p>When treated as a key-value pair, this is the key.</p>
174     *
175     * @return the left element, may be null
176     */
177    public abstract L getLeft();
178
179    /**
180     * <p>Gets the right element from this pair.</p>
181     *
182     * <p>When treated as a key-value pair, this is the value.</p>
183     *
184     * @return the right element, may be null
185     */
186    public abstract R getRight();
187
188    /**
189     * <p>Gets the value from this pair.</p>
190     *
191     * <p>This method implements the {@code Map.Entry} interface returning the
192     * right element as the value.</p>
193     *
194     * @return the right element as the value, may be null
195     */
196    @Override
197    public R getValue() {
198        return getRight();
199    }
200
201    /**
202     * <p>Returns a suitable hash code.
203     * The hash code follows the definition in {@code Map.Entry}.</p>
204     *
205     * @return the hash code
206     */
207    @Override
208    public int hashCode() {
209        // see Map.Entry API specification
210        return Objects.hashCode(getKey()) ^ Objects.hashCode(getValue());
211    }
212
213    /**
214     * <p>Returns a String representation of this pair using the format {@code ($left,$right)}.</p>
215     *
216     * @return a string describing this object, not null
217     */
218    @Override
219    public String toString() {
220        return "(" + getLeft() + ',' + getRight() + ')';
221    }
222
223    /**
224     * <p>Formats the receiver using the given format.</p>
225     *
226     * <p>This uses {@link java.util.Formattable} to perform the formatting. Two variables may
227     * be used to embed the left and right elements. Use {@code %1$s} for the left
228     * element (key) and {@code %2$s} for the right element (value).
229     * The default format used by {@code toString()} is {@code (%1$s,%2$s)}.</p>
230     *
231     * @param format  the format string, optionally containing {@code %1$s} and {@code %2$s}, not null
232     * @return the formatted string, not null
233     */
234    public String toString(final String format) {
235        return String.format(format, getLeft(), getRight());
236    }
237
238}