View Javadoc
1   /*
2    * The contents of this file are subject to the terms of the Common Development and
3    * Distribution License (the License). You may not use this file except in compliance with the
4    * License.
5    *
6    * You can obtain a copy of the License at legal/CDDLv1.0.txt. See the License for the
7    * specific language governing permission and limitations under the License.
8    *
9    * When distributing Covered Software, include this CDDL Header Notice in each file and include
10   * the License file at legal/CDDLv1.0.txt. If applicable, add the following below the CDDL
11   * Header, with the fields enclosed by brackets [] replaced by your own identifying
12   * information: "Portions copyright [year] [name of copyright owner]".
13   *
14   * Copyright 2015-2016 ForgeRock AS.
15   */
16  package org.forgerock.util;
17  
18  import java.util.Comparator;
19  
20  /**
21   * Ordered pair of arbitrary objects. Use of Pair is strictly restricted to internal (non-public) APIs:<br>
22   * - Pair cannot be used in public APIs
23   * - Consider using dedicated classes over Pair. Dedicated classes are more readable while Pair is meaningless.<br>
24   * - Pair should only be used to return two values from a method, just like a tuple. If you need more than two
25   * values, create a dedicated class.
26   *
27   * @param <F>
28   *            type of the first pair element
29   * @param <S>
30   *            type of the second pair element
31   */
32  public final class Pair<F, S> {
33  
34      private static final class ComparablePairComparator
35              <F extends Comparable<F>, S extends Comparable<S>>
36              implements Comparator<Pair<F, S>> {
37          /** {@inheritDoc} */
38          @Override
39          public int compare(Pair<F, S> o1, Pair<F, S> o2) {
40              final int compareResult = o1.getFirst().compareTo(o2.getFirst());
41              if (compareResult == 0) {
42                  return o1.getSecond().compareTo(o2.getSecond());
43              }
44              return compareResult;
45          }
46      }
47  
48      /** An empty Pair. */
49      public static final Pair<?, ?> EMPTY = Pair.of(null, null);
50  
51      /**
52       * {@link Comparator} for {@link Pair}s made of {@link Comparable} elements.
53       */
54      @SuppressWarnings("rawtypes")
55      public static final Comparator COMPARATOR = new ComparablePairComparator();
56  
57      /** The first pair element. */
58      private final F first;
59  
60      /** The second pair element. */
61      private final S second;
62  
63      /**
64       * Creates a pair.
65       *
66       * @param first
67       *            the first element of the constructed pair
68       * @param second
69       *            the second element of the constructed pair
70       */
71      private Pair(F first, S second) {
72          this.first = first;
73          this.second = second;
74      }
75  
76      /**
77       * Creates a new {@code Pair}.
78       *
79       * @param first
80       *            the first element of the constructed pair
81       * @param second
82       *            the second element of the constructed pair
83       * @param <F>
84       *            type of the first pair element
85       * @param <S>
86       *            type of the second pair element
87       * @return A new Pair built with the provided elements
88       */
89      public static <F, S> Pair<F, S> of(F first, S second) {
90          return new Pair<>(first, second);
91      }
92  
93      /**
94       * Returns an empty Pair matching the required types.
95       *
96       * @param <F>
97       *            type of the first pair element
98       * @param <S>
99       *            type of the second pair element
100      * @return An empty Pair matching the required types
101      */
102     @SuppressWarnings("unchecked")
103     public static <F, S> Pair<F, S> empty() {
104         return (Pair<F, S>) EMPTY;
105     }
106 
107     /**
108      * Returns a comparator for Pairs of comparable objects.
109      *
110      * @param <F>
111      *            type of the first pair element
112      * @param <S>
113      *            type of the second pair element
114      * @return a comparator for Pairs of comparable objects.
115      */
116     @SuppressWarnings("unchecked")
117     public static <F extends Comparable<F>, S extends Comparable<S>> Comparator<Pair<F, S>> getPairComparator() {
118         return COMPARATOR;
119     }
120 
121     /**
122      * Returns the first element of this pair.
123      *
124      * @return the first element of this pair
125      */
126     public F getFirst() {
127         return first;
128     }
129 
130     /**
131      * Returns the second element of this pair.
132      *
133      * @return the second element of this pair
134      */
135     public S getSecond() {
136         return second;
137     }
138 
139     /** {@inheritDoc} */
140     @Override
141     public int hashCode() {
142         final int prime = 31;
143         int result = 1;
144         result = prime * result + ((first == null) ? 0 : first.hashCode());
145         result = prime * result + ((second == null) ? 0 : second.hashCode());
146         return result;
147     }
148 
149     /** {@inheritDoc} */
150     @Override
151     public boolean equals(Object obj) {
152         if (this == obj) {
153             return true;
154         }
155 
156         if (!(obj instanceof Pair)) {
157             return false;
158         }
159 
160         Pair<?, ?> other = (Pair<?, ?>) obj;
161         if (first == null) {
162             if (other.first != null) {
163                 return false;
164             }
165         } else if (!first.equals(other.first)) {
166             return false;
167         }
168 
169         if (second == null) {
170             if (other.second != null) {
171                 return false;
172             }
173         } else {
174             return second.equals(other.second);
175         }
176 
177         return true;
178     }
179 
180     /** {@inheritDoc} */
181     @Override
182     public String toString() {
183         return "Pair [" + first + ", " + second + "]";
184     }
185 }