View Javadoc
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    *      http://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.collections4.comparators;
18  
19  import java.io.Serializable;
20  import java.util.Comparator;
21  import java.util.Objects;
22  
23  import org.apache.commons.collections4.ComparatorUtils;
24  
25  /**
26   * A Comparator that will compare nulls to be either lower or higher than
27   * other objects.
28   *
29   * @param <E> the type of objects compared by this comparator
30   * @since 2.0
31   */
32  public class NullComparator<E> implements Comparator<E>, Serializable {
33  
34      /** Serialization version. */
35      private static final long serialVersionUID = -5820772575483504339L;
36  
37      /**
38       *  The comparator to use when comparing two non-{@code null} objects.
39       **/
40      private final Comparator<? super E> nonNullComparator;
41  
42      /**
43       *  Specifies whether a {@code null} are compared as higher than
44       *  non-{@code null} objects.
45       **/
46      private final boolean nullsAreHigh;
47  
48      /**
49       *  Construct an instance that sorts {@code null} higher than any
50       *  non-{@code null} object it is compared with. When comparing two
51       *  non-{@code null} objects, the {@link ComparableComparator} is
52       *  used.
53       **/
54      public NullComparator() {
55          this(ComparatorUtils.NATURAL_COMPARATOR, true);
56      }
57  
58      /**
59       *  Construct an instance that sorts {@code null} higher or lower than
60       *  any non-{@code null} object it is compared with.  When comparing
61       *  two non-{@code null} objects, the {@link ComparableComparator} is
62       *  used.
63       *
64       *  @param nullsAreHigh a {@code true} value indicates that
65       *  {@code null} should be compared as higher than a
66       *  non-{@code null} object.  A {@code false} value indicates
67       *  that {@code null} should be compared as lower than a
68       *  non-{@code null} object.
69       **/
70      public NullComparator(final boolean nullsAreHigh) {
71          this(ComparatorUtils.NATURAL_COMPARATOR, nullsAreHigh);
72      }
73  
74      /**
75       *  Construct an instance that sorts {@code null} higher than any
76       *  non-{@code null} object it is compared with.  When comparing two
77       *  non-{@code null} objects, the specified {@link Comparator} is
78       *  used.
79       *
80       *  @param nonNullComparator the comparator to use when comparing two
81       *  non-{@code null} objects.  This argument cannot be
82       *  {@code null}
83       *
84       *  @throws NullPointerException if {@code nonNullComparator} is
85       *  {@code null}
86       **/
87      public NullComparator(final Comparator<? super E> nonNullComparator) {
88          this(nonNullComparator, true);
89      }
90  
91      /**
92       *  Construct an instance that sorts {@code null} higher or lower than
93       *  any non-{@code null} object it is compared with.  When comparing
94       *  two non-{@code null} objects, the specified {@link Comparator} is
95       *  used.
96       *
97       *  @param nonNullComparator the comparator to use when comparing two
98       *  non-{@code null} objects. This argument cannot be
99       *  {@code null}
100      *
101      *  @param nullsAreHigh a {@code true} value indicates that
102      *  {@code null} should be compared as higher than a
103      *  non-{@code null} object.  A {@code false} value indicates
104      *  that {@code null} should be compared as lower than a
105      *  non-{@code null} object.
106      *
107      *  @throws NullPointerException if {@code nonNullComparator} is
108      *  {@code null}
109      **/
110     public NullComparator(final Comparator<? super E> nonNullComparator, final boolean nullsAreHigh) {
111         this.nonNullComparator = Objects.requireNonNull(nonNullComparator, "nonNullComparator");
112         this.nullsAreHigh = nullsAreHigh;
113     }
114 
115     /**
116      *  Perform a comparison between two objects.  If both objects are
117      *  {@code null}, a {@code 0} value is returned.  If one object
118      *  is {@code null} and the other is not, the result is determined on
119      *  whether the Comparator was constructed to have nulls as higher or lower
120      *  than other objects.  If neither object is {@code null}, an
121      *  underlying comparator specified in the constructor (or the default) is
122      *  used to compare the non-{@code null} objects.
123      *
124      *  @param o1  the first object to compare
125      *  @param o2  the object to compare it to.
126      *  @return {@code -1} if {@code o1} is "lower" than (less than,
127      *  before, etc.) {@code o2}; {@code 1} if {@code o1} is
128      *  "higher" than (greater than, after, etc.) {@code o2}; or
129      *  {@code 0} if {@code o1} and {@code o2} are equal.
130      **/
131     @Override
132     public int compare(final E o1, final E o2) {
133         if (o1 == o2) {
134             return 0;
135         }
136         if (o1 == null) {
137             return this.nullsAreHigh ? 1 : -1;
138         }
139         if (o2 == null) {
140             return this.nullsAreHigh ? -1 : 1;
141         }
142         return this.nonNullComparator.compare(o1, o2);
143     }
144 
145     /**
146      *  Determines whether the specified object represents a comparator that is
147      *  equal to this comparator.
148      *
149      *  @param obj  the object to compare this comparator with.
150      *
151      *  @return {@code true} if the specified object is a NullComparator
152      *  with equivalent {@code null} comparison behavior
153      *  (i.e. {@code null} high or low) and with equivalent underlying
154      *  non-{@code null} object comparators.
155      **/
156     @Override
157     public boolean equals(final Object obj) {
158         if (obj == null) {
159             return false;
160         }
161         if (obj == this) {
162             return true;
163         }
164         if (!obj.getClass().equals(this.getClass())) {
165             return false;
166         }
167 
168         final NullComparator<?> other = (NullComparator<?>) obj;
169 
170         return this.nullsAreHigh == other.nullsAreHigh &&
171                 this.nonNullComparator.equals(other.nonNullComparator);
172     }
173 
174     /**
175      *  Implement a hash code for this comparator that is consistent with
176      *  {@link #equals(Object)}.
177      *
178      *  @return a hash code for this comparator.
179      **/
180     @Override
181     public int hashCode() {
182         return (nullsAreHigh ? -1 : 1) * nonNullComparator.hashCode();
183     }
184 }