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