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 * https://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 * @throws NullPointerException if {@code nonNullComparator} is 084 * {@code null} 085 */ 086 public NullComparator(final Comparator<? super E> nonNullComparator) { 087 this(nonNullComparator, true); 088 } 089 090 /** 091 * Construct an instance that sorts {@code null} higher or lower than 092 * any non-{@code null} object it is compared with. When comparing 093 * two non-{@code null} objects, the specified {@link Comparator} is 094 * used. 095 * 096 * @param nonNullComparator The comparator to use when comparing two 097 * non-{@code null} objects. This argument cannot be 098 * {@code null} 099 * @param nullsAreHigh A {@code true} value indicates that 100 * {@code null} should be compared as higher than a 101 * non-{@code null} object. A {@code false} value indicates 102 * that {@code null} should be compared as lower than a 103 * non-{@code null} object. 104 * @throws NullPointerException if {@code nonNullComparator} is 105 * {@code null} 106 */ 107 public NullComparator(final Comparator<? super E> nonNullComparator, final boolean nullsAreHigh) { 108 this.nonNullComparator = Objects.requireNonNull(nonNullComparator, "nonNullComparator"); 109 this.nullsAreHigh = nullsAreHigh; 110 } 111 112 /** 113 * Perform a comparison between two objects. If both objects are 114 * {@code null}, a {@code 0} value is returned. If one object 115 * is {@code null} and the other is not, the result is determined on 116 * whether the Comparator was constructed to have nulls as higher or lower 117 * than other objects. If neither object is {@code null}, an 118 * underlying comparator specified in the constructor (or the default) is 119 * used to compare the non-{@code null} objects. 120 * 121 * @param o1 The first object to compare 122 * @param o2 The object to compare it to. 123 * @return {@code -1} if {@code o1} is "lower" than (less than, 124 * before, etc.) {@code o2}; {@code 1} if {@code o1} is 125 * "higher" than (greater than, after, etc.) {@code o2}; or 126 * {@code 0} if {@code o1} and {@code o2} are equal. 127 */ 128 @Override 129 public int compare(final E o1, final E o2) { 130 if (o1 == o2) { 131 return 0; 132 } 133 if (o1 == null) { 134 return nullsAreHigh ? 1 : -1; 135 } 136 if (o2 == null) { 137 return nullsAreHigh ? -1 : 1; 138 } 139 return nonNullComparator.compare(o1, o2); 140 } 141 142 /** 143 * Determines whether the specified object represents a comparator that is 144 * equal to this comparator. 145 * 146 * @param obj The object to compare this comparator with. 147 * @return {@code true} if the specified object is a NullComparator 148 * with equivalent {@code null} comparison behavior 149 * (i.e. {@code null} high or low) and with equivalent underlying 150 * non-{@code null} object comparators. 151 */ 152 @Override 153 public boolean equals(final Object obj) { 154 if (obj == null) { 155 return false; 156 } 157 if (obj == this) { 158 return true; 159 } 160 if (!obj.getClass().equals(this.getClass())) { 161 return false; 162 } 163 164 final NullComparator<?> other = (NullComparator<?>) obj; 165 166 return nullsAreHigh == other.nullsAreHigh && 167 nonNullComparator.equals(other.nonNullComparator); 168 } 169 170 /** 171 * Implement a hash code for this comparator that is consistent with 172 * {@link #equals(Object)}. 173 * 174 * @return A hash code for this comparator. 175 */ 176 @Override 177 public int hashCode() { 178 return (nullsAreHigh ? -1 : 1) * nonNullComparator.hashCode(); 179 } 180}