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.collections4.comparators; 018 019import java.io.Serializable; 020import java.util.Comparator; 021import java.util.Objects; 022 023import org.apache.commons.collections4.ComparatorUtils; 024 025/** 026 * A Comparator that will compare nulls to be either lower or higher than 027 * other objects. 028 * 029 * @param <E> the type of objects compared by this comparator 030 * @since 2.0 031 */ 032public class NullComparator<E> implements Comparator<E>, Serializable { 033 034 /** Serialization version. */ 035 private static final long serialVersionUID = -5820772575483504339L; 036 037 /** 038 * The comparator to use when comparing two non-{@code null} objects. 039 **/ 040 private final Comparator<? super E> nonNullComparator; 041 042 /** 043 * Specifies whether a {@code null} are compared as higher than 044 * non-{@code null} objects. 045 **/ 046 private final boolean nullsAreHigh; 047 048 /** 049 * Construct an instance that sorts {@code null} higher than any 050 * non-{@code null} object it is compared with. When comparing two 051 * non-{@code null} objects, the {@link ComparableComparator} is 052 * used. 053 **/ 054 public NullComparator() { 055 this(ComparatorUtils.NATURAL_COMPARATOR, true); 056 } 057 058 /** 059 * Construct an instance that sorts {@code null} higher or lower than 060 * any non-{@code null} object it is compared with. When comparing 061 * two non-{@code null} objects, the {@link ComparableComparator} is 062 * used. 063 * 064 * @param nullsAreHigh a {@code true} value indicates that 065 * {@code null} should be compared as higher than a 066 * non-{@code null} object. A {@code false} value indicates 067 * that {@code null} should be compared as lower than a 068 * non-{@code null} object. 069 **/ 070 public NullComparator(final boolean nullsAreHigh) { 071 this(ComparatorUtils.NATURAL_COMPARATOR, nullsAreHigh); 072 } 073 074 /** 075 * Construct an instance that sorts {@code null} higher than any 076 * non-{@code null} object it is compared with. When comparing two 077 * non-{@code null} objects, the specified {@link Comparator} is 078 * used. 079 * 080 * @param nonNullComparator the comparator to use when comparing two 081 * non-{@code null} objects. This argument cannot be 082 * {@code null} 083 * 084 * @throws NullPointerException if {@code nonNullComparator} is 085 * {@code null} 086 **/ 087 public NullComparator(final Comparator<? super E> nonNullComparator) { 088 this(nonNullComparator, true); 089 } 090 091 /** 092 * Construct an instance that sorts {@code null} higher or lower than 093 * any non-{@code null} object it is compared with. When comparing 094 * two non-{@code null} objects, the specified {@link Comparator} is 095 * used. 096 * 097 * @param nonNullComparator the comparator to use when comparing two 098 * non-{@code null} objects. This argument cannot be 099 * {@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}