    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}