mirror of
https://github.com/apache/commons-lang.git
synced 2025-02-06 10:08:32 +00:00
Refactor Range with lots of new methods
git-svn-id: https://svn.apache.org/repos/asf/commons/proper/lang/trunk@1127565 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
f5682c4c70
commit
0ad6c30b0e
@ -18,21 +18,23 @@
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Comparator;
|
||||
import java.util.Formattable;
|
||||
|
||||
/**
|
||||
* <p>{@code Range} represents an immutable range of comparables of the same type.</p>
|
||||
* <p>The objects need to either be implementations of {@code java.lang.Comparable}
|
||||
* or you need to supply a {@code java.util.Comparator}. </p>
|
||||
* <p>An immutable range of objects from a minimum to maximum point inclusive.</p>
|
||||
*
|
||||
* <p>The objects need to either be implementations of {@code Comparable}
|
||||
* or you need to supply a {@code Comparator}. </p>
|
||||
*
|
||||
* <p>#ThreadSafe# if the comparables are thread-safe</p>
|
||||
* <p>#ThreadSafe# if the objects and comparator are thread-safe</p>
|
||||
*
|
||||
* @since 3.0
|
||||
* @version $Id$
|
||||
*/
|
||||
public final class Range<T> implements Serializable {
|
||||
|
||||
/**
|
||||
* Required for serialization support.
|
||||
*
|
||||
* Serialization version.
|
||||
* @see java.io.Serializable
|
||||
*/
|
||||
private static final long serialVersionUID = 1L;
|
||||
@ -41,124 +43,123 @@ public final class Range<T> implements Serializable {
|
||||
* The ordering scheme used in this range.
|
||||
*/
|
||||
private final Comparator<T> comparator;
|
||||
|
||||
/**
|
||||
* The minimum value in this range (inclusive).
|
||||
*/
|
||||
private final T minimum;
|
||||
|
||||
/**
|
||||
* The maximum value in this range (inclusive).
|
||||
*/
|
||||
private final T maximum;
|
||||
|
||||
/**
|
||||
* Cached output hashCode (class is immutable).
|
||||
*/
|
||||
private transient int hashCode = 0;
|
||||
|
||||
private transient int hashCode;
|
||||
/**
|
||||
* Cached output toString (class is immutable).
|
||||
*/
|
||||
private transient String toString = null;
|
||||
private transient String toString;
|
||||
|
||||
/**
|
||||
* <p>Constructs a new {@code Range} using the specified
|
||||
* element as both the minimum and maximum in this range.</p>
|
||||
* <p>The range uses the natural ordering of the elements to
|
||||
* determine where values lie in the range.</p>
|
||||
* <p>Obtains a range using the specified element as both the minimum
|
||||
* and maximum in this range.</p>
|
||||
*
|
||||
* <p>The range uses the natural ordering of the elements to determine where
|
||||
* values lie in the range.</p>
|
||||
*
|
||||
* @param <T> the type of this {@code Range}
|
||||
* @param element the value to use for this range, must not be {@code null}
|
||||
* @return the new range object
|
||||
* @throws IllegalArgumentException if the value is {@code null}
|
||||
* @throws ClassCastException if the value is not Comparable
|
||||
* @param <T> the type of the elements in this range
|
||||
* @param element the value to use for this range, not null
|
||||
* @return the range object, not null
|
||||
* @throws IllegalArgumentException if the element is null
|
||||
* @throws ClassCastException if the element is not {@code Comparable}
|
||||
*/
|
||||
public static <T extends Comparable<T>> Range<T> is(T element) {
|
||||
return new Range<T>(element, element, ComparableComparator.<T>getInstance());
|
||||
return between(element, element, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Constructs a new {@code Range} with the specified
|
||||
* minimum and maximum values (both inclusive).</p>
|
||||
* <p>The range uses the natural ordering of the elements to
|
||||
* determine where values lie in the range.</p>
|
||||
* <p>Obtains a range using the specified element as both the minimum
|
||||
* and maximum in this range.</p>
|
||||
*
|
||||
* <p>The range uses the specified {@code Comparator} to determine where
|
||||
* values lie in the range.</p>
|
||||
*
|
||||
* <p>The arguments may be passed in the order (min,max) or (max,min). The
|
||||
* getMinimum and getMaximum methods will return the correct values.</p>
|
||||
*
|
||||
* @param <T> the type of this {@code Range}
|
||||
* @param element1 first value that defines the edge of the range, inclusive
|
||||
* @param element2 second value that defines the edge of the range, inclusive
|
||||
* @return the new range object
|
||||
* @throws IllegalArgumentException if either value is {@code null}
|
||||
* @throws ClassCastException if either value is not Comparable
|
||||
*/
|
||||
public static <T extends Comparable<T>> Range<T> between(T element1, T element2) {
|
||||
return new Range<T>( element1, element2, ComparableComparator.<T>getInstance());
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Constructs a new {@code Range} using the specified
|
||||
* element as both the minimum and maximum in this range.</p>
|
||||
* <p>The range uses the passed in {@code Comparator} to
|
||||
* determine where values lie in the range.</p>
|
||||
*
|
||||
* @param <T> the type of this {@code Range}
|
||||
* @param <T> the type of the elements in this range
|
||||
* @param element the value to use for this range, must not be {@code null}
|
||||
* @param c comparator to be used
|
||||
* @return the new range object
|
||||
* @throws IllegalArgumentException if the value is {@code null}
|
||||
* @param comparator the comparator to be used, null for natural ordering
|
||||
* @return the range object, not null
|
||||
* @throws IllegalArgumentException if the element is null
|
||||
* @throws ClassCastException if using natural ordering and the elements are not {@code Comparable}
|
||||
*/
|
||||
public static <T> Range<T> is(T element, Comparator<T> c) {
|
||||
return new Range<T>(element, element, c);
|
||||
public static <T> Range<T> is(T element, Comparator<T> comparator) {
|
||||
return between(element, element, comparator);
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Constructs a new {@code Range} with the specified
|
||||
* minimum and maximum values (both inclusive).</p>
|
||||
* <p>The range uses the passed in {@code Comparator} to
|
||||
* determine where values lie in the range.</p>
|
||||
* <p>Obtains a range with the specified minimum and maximum values (both inclusive).</p>
|
||||
*
|
||||
* <p>The range uses the natural ordering of the elements to determine where
|
||||
* values lie in the range.</p>
|
||||
*
|
||||
* <p>The arguments may be passed in the order (min,max) or (max,min). The
|
||||
* getMinimum and getMaximum methods will return the correct values.</p>
|
||||
* <p>The arguments may be passed in the order (min,max) or (max,min).
|
||||
* The getMinimum and getMaximum methods will return the correct values.</p>
|
||||
*
|
||||
* @param <T> the type of this {@code Range}
|
||||
* @param element1 first value that defines the edge of the range, inclusive
|
||||
* @param element2 second value that defines the edge of the range, inclusive
|
||||
* @param c comparator to be used
|
||||
* @return the new range object
|
||||
* @throws IllegalArgumentException if either value is {@code null}
|
||||
* @param <T> the type of the elements in this range
|
||||
* @param fromInclusive the first value that defines the edge of the range, inclusive
|
||||
* @param toInclusive the second value that defines the edge of the range, inclusive
|
||||
* @return the range object, not null
|
||||
* @throws IllegalArgumentException if either element is null
|
||||
* @throws ClassCastException if the elements are not {@code Comparable}
|
||||
*/
|
||||
public static <T> Range<T> between(T element1, T element2, Comparator<T> c) {
|
||||
return new Range<T>(element1, element2, c);
|
||||
public static <T extends Comparable<T>> Range<T> between(T fromInclusive, T toInclusive) {
|
||||
return between(fromInclusive, toInclusive, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new instance of {@code Range}.
|
||||
* <p>Obtains a range with the specified minimum and maximum values (both inclusive).</p>
|
||||
*
|
||||
* <p>The range uses the specified {@code Comparator} to determine where
|
||||
* values lie in the range.</p>
|
||||
*
|
||||
* @param element1 the first element
|
||||
* @param element2 the second element
|
||||
* @param c the comparator to be used
|
||||
* <p>The arguments may be passed in the order (min,max) or (max,min).
|
||||
* The getMinimum and getMaximum methods will return the correct values.</p>
|
||||
*
|
||||
* @param <T> the type of the elements in this range
|
||||
* @param fromInclusive the first value that defines the edge of the range, inclusive
|
||||
* @param toInclusive the second value that defines the edge of the range, inclusive
|
||||
* @param comparator the comparator to be used, null for natural ordering
|
||||
* @return the range object, not null
|
||||
* @throws IllegalArgumentException if either element is null
|
||||
* @throws ClassCastException if using natural ordering and the elements are not {@code Comparable}
|
||||
*/
|
||||
private Range(T element1, T element2, Comparator<T> c) {
|
||||
if(element1 == null || element2 == null) {
|
||||
public static <T> Range<T> between(T fromInclusive, T toInclusive, Comparator<T> comparator) {
|
||||
return new Range<T>(fromInclusive, toInclusive, comparator);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an instance.
|
||||
*
|
||||
* @param element1 the first element, not null
|
||||
* @param element2 the second element, not null
|
||||
* @param comparator the comparator to be used, null for natural ordering
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
private Range(T element1, T element2, Comparator<T> comparator) {
|
||||
if (element1 == null || element2 == null) {
|
||||
throw new IllegalArgumentException("Elements in a range must not be null: element1=" +
|
||||
element1 + ", element2=" + element2);
|
||||
}
|
||||
|
||||
if(c == null) {
|
||||
throw new IllegalArgumentException("Comparator must not be null");
|
||||
if (comparator == null) {
|
||||
comparator = ComparableComparator.INSTANCE;
|
||||
}
|
||||
|
||||
if(c.compare(element1, element2) < 1) {
|
||||
if (comparator.compare(element1, element2) < 1) {
|
||||
this.minimum = element1;
|
||||
this.maximum = element2;
|
||||
} else {
|
||||
this.minimum = element2;
|
||||
this.maximum = element1;
|
||||
}
|
||||
this.comparator = c;
|
||||
this.comparator = comparator;
|
||||
}
|
||||
|
||||
// Accessors
|
||||
@ -167,108 +168,131 @@ private Range(T element1, T element2, Comparator<T> c) {
|
||||
/**
|
||||
* <p>Gets the minimum value in this range.</p>
|
||||
*
|
||||
* @return the minimum value in this range
|
||||
* @return the minimum value in this range, not null
|
||||
*/
|
||||
public T getMinimum() {
|
||||
return this.minimum;
|
||||
return minimum;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Gets the maximum value in this range.</p>
|
||||
*
|
||||
* @return the maximum value in this range
|
||||
* @return the maximum value in this range, not null
|
||||
*/
|
||||
public T getMaximum() {
|
||||
return this.maximum;
|
||||
return maximum;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Gets the comparator being used to determine if objects are within the range. </p>
|
||||
* <p>Gets the comparator being used to determine if objects are within the range.</p>
|
||||
*
|
||||
* <p>Natural ordering uses an internal comparator implementation, thus this
|
||||
* method never returns null. See {@link #isNaturalOrdering()}.</p>
|
||||
*
|
||||
* @return the comparator being used
|
||||
* @return the comparator being used, not null
|
||||
*/
|
||||
public Comparator<T> getComparator() {
|
||||
return this.comparator;
|
||||
return comparator;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Whether or not the Range is using the default natural comparison method
|
||||
* to compare elements. </p>
|
||||
* <p>Whether or not the Range is using the natural ordering of the elements.</p>
|
||||
*
|
||||
* <p>Natural ordering uses an internal comparator implementation, thus this
|
||||
* method is the only way to check if a null comparator was specified.</p>
|
||||
*
|
||||
* @return whether or not the default Comparator is in use
|
||||
* @return true if using natural ordering
|
||||
*/
|
||||
public boolean isDefaultNaturalOrdering() {
|
||||
return this.comparator == ComparableComparator.INSTANCE;
|
||||
public boolean isNaturalOrdering() {
|
||||
return comparator == ComparableComparator.INSTANCE;
|
||||
}
|
||||
|
||||
// Include tests
|
||||
// Element tests
|
||||
//--------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* <p>Tests whether the specified element occurs within this range.</p>
|
||||
* <p>Checks whether the specified element occurs within this range.</p>
|
||||
*
|
||||
* <p>{@code null} is handled and returns {@code false}.</p>
|
||||
*
|
||||
* @param element the element to test, may be {@code null}
|
||||
* @return {@code true} if the specified element occurs within this range
|
||||
* @param element the element to check for, null returns false
|
||||
* @return true if the specified element occurs within this range
|
||||
*/
|
||||
public boolean contains(T element) {
|
||||
if(element == null) {
|
||||
return false;
|
||||
}
|
||||
return (comparator.compare(element, this.minimum) > -1) && (comparator.compare(element, this.maximum) < 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Tests whether the specified element occurs before this range.</p>
|
||||
*
|
||||
* <p>{@code null} is handled and returns {@code false}.</p>
|
||||
*
|
||||
* @param element the element to test, may be {@code null}
|
||||
* @return {@code true} if the specified element occurs before this range
|
||||
*/
|
||||
public boolean elementBefore(T element) {
|
||||
if (element == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return this.comparator.compare(element, this.minimum) < 0;
|
||||
return (comparator.compare(element, minimum) > -1) && (comparator.compare(element, maximum) < 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Tests whether the specified element occurs after this range.</p>
|
||||
* <p>Checks whether this range is after the specified element.</p>
|
||||
*
|
||||
* <p>{@code null} is handled and returns {@code false}.</p>
|
||||
*
|
||||
* @param element the element to test, may be {@code null}
|
||||
* @return {@code true} if the specified element occurs after this range
|
||||
* @param element the element to check for, null returns false
|
||||
* @return true if this range is entirely after the specified element
|
||||
*/
|
||||
public boolean elementAfter(T element) {
|
||||
public boolean isAfter(T element) {
|
||||
if (element == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return this.comparator.compare(element, this.maximum) > 0;
|
||||
return comparator.compare(element, minimum) < 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Tests where the specified element occurs relative to this range.</p>
|
||||
* <p>Checks whether this range starts with the specified element.</p>
|
||||
*
|
||||
* @param element the element to check for, null returns false
|
||||
* @return true if the specified element occurs within this range
|
||||
*/
|
||||
public boolean isStartedBy(T element) {
|
||||
if (element == null) {
|
||||
return false;
|
||||
}
|
||||
return comparator.compare(element, minimum) == 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Checks whether this range starts with the specified element.</p>
|
||||
*
|
||||
* @param element the element to check for, null returns false
|
||||
* @return true if the specified element occurs within this range
|
||||
*/
|
||||
public boolean isEndedBy(T element) {
|
||||
if (element == null) {
|
||||
return false;
|
||||
}
|
||||
return comparator.compare(element, maximum) == 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Checks whether this range is before the specified element.</p>
|
||||
*
|
||||
* @param element the element to check for, null returns false
|
||||
* @return true if this range is entirely before the specified element
|
||||
*/
|
||||
public boolean isBefore(T element) {
|
||||
if (element == null) {
|
||||
return false;
|
||||
}
|
||||
return comparator.compare(element, maximum) > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Checks where the specified element occurs relative to this range.</p>
|
||||
*
|
||||
* <p>The API is reminiscent of the Comparable interface returning {@code -1} if
|
||||
* the element is before the range, {@code 0} if contained within the range and
|
||||
* {@code 1} if the element is after the range. </p>
|
||||
*
|
||||
* @param element the element to test
|
||||
* @param element the element to check for, not null
|
||||
* @return -1, 0 or +1 depending on the element's location relative to the range
|
||||
*/
|
||||
public int elementCompareTo(T element) {
|
||||
if(element == null) {
|
||||
if (element == null) {
|
||||
// Comparable API says throw NPE on null
|
||||
throw new NullPointerException("Element is null");
|
||||
}
|
||||
if(elementBefore(element)) {
|
||||
if (isAfter(element)) {
|
||||
return -1;
|
||||
} else
|
||||
if(elementAfter(element)) {
|
||||
} else if (isBefore(element)) {
|
||||
return 1;
|
||||
} else {
|
||||
return 0;
|
||||
@ -279,40 +303,73 @@ public int elementCompareTo(T element) {
|
||||
//--------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* <p>Tests whether the specified range occurs entirely within this range.</p>
|
||||
* <p>Checks whether this range contains all the elements of the specified range.</p>
|
||||
*
|
||||
* <p>{@code null} is handled and returns {@code false}.</p>
|
||||
* <p>This method may fail if the ranges have two different comparators or element types.</p>
|
||||
*
|
||||
* @param range the range to test, may be {@code null}
|
||||
* @return {@code true} if the specified range occurs entirely within
|
||||
* this range; otherwise, {@code false}
|
||||
* @throws IllegalArgumentException if the {@code Range} cannot be compared
|
||||
* @param otherRange the range to check, null returns false
|
||||
* @return true if this range contains the specified range
|
||||
* @throws RuntimeException if ranges cannot be compared
|
||||
*/
|
||||
public boolean containsAll(Range<T> range) {
|
||||
if (range == null) {
|
||||
public boolean containsRange(Range<T> otherRange) {
|
||||
if (otherRange == null) {
|
||||
return false;
|
||||
}
|
||||
return contains(range.getMinimum())
|
||||
&& contains(range.getMaximum());
|
||||
return contains(otherRange.minimum)
|
||||
&& contains(otherRange.maximum);
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Tests whether the specified range overlaps with this range.</p>
|
||||
* <p>Checks whether this range is completely after the specified range.</p>
|
||||
*
|
||||
* <p>{@code null} is handled and returns {@code false}.</p>
|
||||
* <p>This method may fail if the ranges have two different comparators or element types.</p>
|
||||
*
|
||||
* @param range the range to test, may be {@code null}
|
||||
* @return {@code true} if the specified range overlaps with this
|
||||
* range; otherwise, {@code false}
|
||||
* @throws IllegalArgumentException if the {@code Range} cannot be compared
|
||||
* @param otherRange the range to check, null returns false
|
||||
* @return true if this range is completely after the specified range
|
||||
* @throws RuntimeException if ranges cannot be compared
|
||||
*/
|
||||
public boolean overlapsWith(Range<T> range) {
|
||||
if (range == null) {
|
||||
public boolean isAfterRange(Range<T> otherRange) {
|
||||
if (otherRange == null) {
|
||||
return false;
|
||||
}
|
||||
return range.contains(this.minimum)
|
||||
|| range.contains(this.maximum)
|
||||
|| contains(range.getMinimum());
|
||||
return isAfter(otherRange.maximum);
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Checks whether this range is overlapped by the specified range.</p>
|
||||
*
|
||||
* <p>Two ranges overlap if there is at least one element in common.</p>
|
||||
*
|
||||
* <p>This method may fail if the ranges have two different comparators or element types.</p>
|
||||
*
|
||||
* @param otherRange the range to test, null returns false
|
||||
* @return true if the specified range overlaps with this
|
||||
* range; otherwise, {@code false}
|
||||
* @throws RuntimeException if ranges cannot be compared
|
||||
*/
|
||||
public boolean isOverlappedBy(Range<T> otherRange) {
|
||||
if (otherRange == null) {
|
||||
return false;
|
||||
}
|
||||
return otherRange.contains(minimum)
|
||||
|| otherRange.contains(maximum)
|
||||
|| contains(otherRange.minimum);
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Checks whether this range is completely before the specified range.</p>
|
||||
*
|
||||
* <p>This method may fail if the ranges have two different comparators or element types.</p>
|
||||
*
|
||||
* @param otherRange the range to check, null returns false
|
||||
* @return true if this range is completely before the specified range
|
||||
* @throws RuntimeException if ranges cannot be compared
|
||||
*/
|
||||
public boolean isBeforeRange(Range<T> otherRange) {
|
||||
if (otherRange == null) {
|
||||
return false;
|
||||
}
|
||||
return isBefore(otherRange.minimum);
|
||||
}
|
||||
|
||||
// Basics
|
||||
@ -321,10 +378,11 @@ public boolean overlapsWith(Range<T> range) {
|
||||
/**
|
||||
* <p>Compares this range to another object to test if they are equal.</p>.
|
||||
*
|
||||
* <p>To be equal, the class, minimum and maximum must be equal.</p>
|
||||
* <p>To be equal, the minimum and maximum values must be equal, which
|
||||
* ignores any differences in the comparator.</p>
|
||||
*
|
||||
* @param obj the reference object with which to compare
|
||||
* @return {@code true} if this object is equal
|
||||
* @return true if this object is equal
|
||||
*/
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
@ -335,13 +393,13 @@ public boolean equals(Object obj) {
|
||||
} else {
|
||||
@SuppressWarnings("unchecked") // OK because we checked the class above
|
||||
Range<T> range = (Range<T>) obj;
|
||||
return getMinimum().equals(range.getMinimum()) &&
|
||||
getMaximum().equals(range.getMaximum());
|
||||
return minimum.equals(range.minimum) &&
|
||||
maximum.equals(range.maximum);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Gets a hashCode for the range.</p>
|
||||
* <p>Gets a suitable hash code for the range.</p>
|
||||
*
|
||||
* @return a hash code value for this object
|
||||
*/
|
||||
@ -351,8 +409,8 @@ public int hashCode() {
|
||||
if (hashCode == 0) {
|
||||
result = 17;
|
||||
result = 37 * result + getClass().hashCode();
|
||||
result = 37 * result + this.minimum.hashCode();
|
||||
result = 37 * result + this.maximum.hashCode();
|
||||
result = 37 * result + minimum.hashCode();
|
||||
result = 37 * result + maximum.hashCode();
|
||||
hashCode = result;
|
||||
}
|
||||
return result;
|
||||
@ -361,7 +419,7 @@ public int hashCode() {
|
||||
/**
|
||||
* <p>Gets the range as a {@code String}.</p>
|
||||
*
|
||||
* <p>The format of the String is 'Range[<i>min</i>,<i>max</i>]'.</p>
|
||||
* <p>The format of the String is '[<i>min</i>..<i>max</i>]'.</p>
|
||||
*
|
||||
* @return the {@code String} representation of this range
|
||||
*/
|
||||
@ -370,10 +428,10 @@ public String toString() {
|
||||
String result = toString;
|
||||
if (result == null) {
|
||||
StringBuilder buf = new StringBuilder(32);
|
||||
buf.append("Range[");
|
||||
buf.append(this.minimum);
|
||||
buf.append(',');
|
||||
buf.append(this.maximum);
|
||||
buf.append('[');
|
||||
buf.append(minimum);
|
||||
buf.append("..");
|
||||
buf.append(maximum);
|
||||
buf.append(']');
|
||||
result = buf.toString();
|
||||
toString = result;
|
||||
@ -381,54 +439,29 @@ public String toString() {
|
||||
return result;
|
||||
}
|
||||
|
||||
// Taken from Commons Collections - documentation removed as not a public class
|
||||
private static class ComparableComparator<E extends Comparable<? super E>> implements Comparator<E>, Serializable {
|
||||
/**
|
||||
* <p>Formats the receiver using the given format.</p>
|
||||
*
|
||||
* <p>This uses {@link Formattable} to perform the formatting. Three variables may
|
||||
* be used to embed the minimum, maximum and comparator.
|
||||
* Use {@code %1$s} for the minimum element, {@code %2$s} for the maximum element
|
||||
* and {@code %3$s} for the comparator.
|
||||
* The default format used by {@code toString()} is {@code [%1$s..%2$s]}.</p>
|
||||
*
|
||||
* @param format the format string, optionally containing {@code %1$s}, {@code %2$s} and {@code %3$s}, not null
|
||||
* @return the formatted string, not null
|
||||
*/
|
||||
public String toString(String format) {
|
||||
return String.format(format, minimum, maximum, comparator);
|
||||
}
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@SuppressWarnings("rawtypes") // Comparator works for all types
|
||||
public static final ComparableComparator<?> INSTANCE = new ComparableComparator();
|
||||
|
||||
/**
|
||||
* Returns a comparator for the specified {@code Comparable} type.
|
||||
*
|
||||
* @param <E> the {@code Comparable} type
|
||||
* @return the comparator for this type
|
||||
*/
|
||||
@SuppressWarnings("unchecked") // OK to cast, because comparator works for all types
|
||||
public static <E extends Comparable<? super E>> ComparableComparator<E> getInstance() {
|
||||
return (ComparableComparator<E>) INSTANCE;
|
||||
//-----------------------------------------------------------------------
|
||||
@SuppressWarnings({"rawtypes", "unchecked"})
|
||||
private enum ComparableComparator implements Comparator {
|
||||
INSTANCE;
|
||||
public int compare(Object obj1, Object obj2) {
|
||||
return ((Comparable) obj1).compareTo(obj2);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new instance of {@code ComparableComparator}.
|
||||
*/
|
||||
public ComparableComparator() {
|
||||
super();
|
||||
}
|
||||
|
||||
/**
|
||||
* Compares two objects.
|
||||
*
|
||||
* @param obj1 the first object
|
||||
* @param obj2 the second object
|
||||
* @return the result of the comparison
|
||||
*/
|
||||
public int compare(E obj1, E obj2) {
|
||||
return obj1.compareTo(obj2);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return "ComparableComparator".hashCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object object) {
|
||||
return (this == object) ||
|
||||
((null != object) && (object.getClass().equals(this.getClass())));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -53,8 +53,8 @@ public void setUp() {
|
||||
doubleRange = Range.between((double) 10, (double) 20);
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
@SuppressWarnings({ "rawtypes", "unchecked" })
|
||||
public void testComparableConstructors() {
|
||||
Comparable c =
|
||||
new Comparable() {
|
||||
@ -62,8 +62,10 @@ public int compareTo(Object other) {
|
||||
return 1;
|
||||
}
|
||||
};
|
||||
Range.is(c);
|
||||
Range.between(c, c);
|
||||
Range r1 = Range.is(c);
|
||||
Range r2 = Range.between(c, c);
|
||||
assertEquals(true, r1.isNaturalOrdering());
|
||||
assertEquals(true, r2.isNaturalOrdering());
|
||||
}
|
||||
|
||||
public void testIsWithCompare(){
|
||||
@ -103,16 +105,14 @@ public int compare(Integer o1, Integer o2) {
|
||||
assertTrue("should contain -11",rb.contains(-11));
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
public void testRangeOfChars() {
|
||||
Range<Character> chars = Range.between('a', 'z');
|
||||
assertTrue(chars.contains('b'));
|
||||
assertFalse(chars.contains('B'));
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
public void testEqualsObject() {
|
||||
assertEquals(byteRange, byteRange);
|
||||
assertEquals(byteRange, byteRange2);
|
||||
@ -128,29 +128,32 @@ public void testEqualsObject() {
|
||||
public void testHashCode() {
|
||||
assertEquals(byteRange.hashCode(), byteRange2.hashCode());
|
||||
assertFalse(byteRange.hashCode() == byteRange3.hashCode());
|
||||
|
||||
|
||||
assertEquals(intRange.hashCode(), intRange.hashCode());
|
||||
assertTrue(intRange.hashCode() != 0);
|
||||
}
|
||||
|
||||
public void testToString() {
|
||||
assertNotNull(byteRange.toString());
|
||||
|
||||
|
||||
String str = intRange.toString();
|
||||
assertEquals("Range[10,20]", str);
|
||||
// assertSame(str, intRange.toString()); // no longer passes - does it matter?
|
||||
assertEquals("Range[-20,-10]", Range.between(-20, -10).toString());
|
||||
assertEquals("[10..20]", str);
|
||||
assertEquals("[-20..-10]", Range.between(-20, -10).toString());
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
public void testToStringFormat() {
|
||||
String str = intRange.toString("From %1$s to %2$s");
|
||||
assertEquals("From 10 to 20", str);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
public void testGetMinimum() {
|
||||
assertEquals(10, (int) intRange.getMinimum());
|
||||
assertEquals(10L, (long) longRange.getMinimum());
|
||||
assertEquals(10f, floatRange.getMinimum(), 0.00001f);
|
||||
assertEquals(10d, doubleRange.getMinimum(), 0.00001d);
|
||||
}
|
||||
|
||||
|
||||
public void testGetMaximum() {
|
||||
assertEquals(20, (int) intRange.getMaximum());
|
||||
assertEquals(20L, (long) longRange.getMaximum());
|
||||
@ -168,24 +171,44 @@ public void testContains() {
|
||||
assertFalse(intRange.contains(25));
|
||||
}
|
||||
|
||||
public void testElementBefore() {
|
||||
assertFalse(intRange.elementBefore(null));
|
||||
public void testIsAfter() {
|
||||
assertFalse(intRange.isAfter(null));
|
||||
|
||||
assertTrue(intRange.elementBefore(5));
|
||||
assertFalse(intRange.elementBefore(10));
|
||||
assertFalse(intRange.elementBefore(15));
|
||||
assertFalse(intRange.elementBefore(20));
|
||||
assertFalse(intRange.elementBefore(25));
|
||||
assertTrue(intRange.isAfter(5));
|
||||
assertFalse(intRange.isAfter(10));
|
||||
assertFalse(intRange.isAfter(15));
|
||||
assertFalse(intRange.isAfter(20));
|
||||
assertFalse(intRange.isAfter(25));
|
||||
}
|
||||
|
||||
public void testElementAfter() {
|
||||
assertFalse(intRange.elementAfter(null));
|
||||
public void testIsStartedBy() {
|
||||
assertFalse(intRange.isStartedBy(null));
|
||||
|
||||
assertFalse(intRange.elementAfter(5));
|
||||
assertFalse(intRange.elementAfter(10));
|
||||
assertFalse(intRange.elementAfter(15));
|
||||
assertFalse(intRange.elementAfter(20));
|
||||
assertTrue(intRange.elementAfter(25));
|
||||
assertFalse(intRange.isStartedBy(5));
|
||||
assertTrue(intRange.isStartedBy(10));
|
||||
assertFalse(intRange.isStartedBy(15));
|
||||
assertFalse(intRange.isStartedBy(20));
|
||||
assertFalse(intRange.isStartedBy(25));
|
||||
}
|
||||
|
||||
public void testIsEndedBy() {
|
||||
assertFalse(intRange.isEndedBy(null));
|
||||
|
||||
assertFalse(intRange.isEndedBy(5));
|
||||
assertFalse(intRange.isEndedBy(10));
|
||||
assertFalse(intRange.isEndedBy(15));
|
||||
assertTrue(intRange.isEndedBy(20));
|
||||
assertFalse(intRange.isEndedBy(25));
|
||||
}
|
||||
|
||||
public void testIsBefore() {
|
||||
assertFalse(intRange.isBefore(null));
|
||||
|
||||
assertFalse(intRange.isBefore(5));
|
||||
assertFalse(intRange.isBefore(10));
|
||||
assertFalse(intRange.isBefore(15));
|
||||
assertFalse(intRange.isBefore(20));
|
||||
assertTrue(intRange.isBefore(25));
|
||||
}
|
||||
|
||||
public void testElementCompareTo() {
|
||||
@ -203,72 +226,100 @@ public void testElementCompareTo() {
|
||||
assertEquals(1, intRange.elementCompareTo(25));
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
public void testContainsAll() {
|
||||
//-----------------------------------------------------------------------
|
||||
public void testContainsRange() {
|
||||
|
||||
// null handling
|
||||
assertFalse(intRange.containsAll(null));
|
||||
assertFalse(intRange.containsRange(null));
|
||||
|
||||
// easy inside range
|
||||
assertTrue(intRange.containsAll(Range.between(12, 18)));
|
||||
assertTrue(intRange.containsRange(Range.between(12, 18)));
|
||||
|
||||
// outside range on each side
|
||||
assertFalse(intRange.containsAll(Range.between(32, 45)));
|
||||
assertFalse(intRange.containsAll(Range.between(2, 8)));
|
||||
assertFalse(intRange.containsRange(Range.between(32, 45)));
|
||||
assertFalse(intRange.containsRange(Range.between(2, 8)));
|
||||
|
||||
// equals range
|
||||
assertTrue(intRange.containsAll(Range.between(10, 20)));
|
||||
assertTrue(intRange.containsRange(Range.between(10, 20)));
|
||||
|
||||
// overlaps
|
||||
assertFalse(intRange.containsAll(Range.between(9, 14)));
|
||||
assertFalse(intRange.containsAll(Range.between(16, 21)));
|
||||
assertFalse(intRange.containsRange(Range.between(9, 14)));
|
||||
assertFalse(intRange.containsRange(Range.between(16, 21)));
|
||||
|
||||
// touches lower boundary
|
||||
assertTrue(intRange.containsAll(Range.between(10, 19)));
|
||||
assertFalse(intRange.containsAll(Range.between(10, 21)));
|
||||
assertTrue(intRange.containsRange(Range.between(10, 19)));
|
||||
assertFalse(intRange.containsRange(Range.between(10, 21)));
|
||||
|
||||
// touches upper boundary
|
||||
assertTrue(intRange.containsAll(Range.between(11, 20)));
|
||||
assertFalse(intRange.containsAll(Range.between(9, 20)));
|
||||
assertTrue(intRange.containsRange(Range.between(11, 20)));
|
||||
assertFalse(intRange.containsRange(Range.between(9, 20)));
|
||||
|
||||
// negative
|
||||
assertFalse(intRange.containsAll(Range.between(-11, -18)));
|
||||
|
||||
assertFalse(intRange.containsRange(Range.between(-11, -18)));
|
||||
}
|
||||
|
||||
public void testOverlapsWith() {
|
||||
public void testIsAfterRange() {
|
||||
assertFalse(intRange.isAfterRange(null));
|
||||
|
||||
assertTrue(intRange.isAfterRange(Range.between(5, 9)));
|
||||
|
||||
assertFalse(intRange.isAfterRange(Range.between(5, 10)));
|
||||
assertFalse(intRange.isAfterRange(Range.between(5, 20)));
|
||||
assertFalse(intRange.isAfterRange(Range.between(5, 25)));
|
||||
assertFalse(intRange.isAfterRange(Range.between(15, 25)));
|
||||
|
||||
assertFalse(intRange.isAfterRange(Range.between(21, 25)));
|
||||
|
||||
assertFalse(intRange.isAfterRange(Range.between(10, 20)));
|
||||
}
|
||||
|
||||
public void testIsOverlappedBy() {
|
||||
|
||||
// null handling
|
||||
assertFalse(intRange.overlapsWith(null));
|
||||
assertFalse(intRange.isOverlappedBy(null));
|
||||
|
||||
// easy inside range
|
||||
assertTrue(intRange.overlapsWith(Range.between(12, 18)));
|
||||
assertTrue(intRange.isOverlappedBy(Range.between(12, 18)));
|
||||
|
||||
// outside range on each side
|
||||
assertFalse(intRange.overlapsWith(Range.between(32, 45)));
|
||||
assertFalse(intRange.overlapsWith(Range.between(2, 8)));
|
||||
assertFalse(intRange.isOverlappedBy(Range.between(32, 45)));
|
||||
assertFalse(intRange.isOverlappedBy(Range.between(2, 8)));
|
||||
|
||||
// equals range
|
||||
assertTrue(intRange.overlapsWith(Range.between(10, 20)));
|
||||
assertTrue(intRange.isOverlappedBy(Range.between(10, 20)));
|
||||
|
||||
// overlaps
|
||||
assertTrue(intRange.overlapsWith(Range.between(9, 14)));
|
||||
assertTrue(intRange.overlapsWith(Range.between(16, 21)));
|
||||
assertTrue(intRange.isOverlappedBy(Range.between(9, 14)));
|
||||
assertTrue(intRange.isOverlappedBy(Range.between(16, 21)));
|
||||
|
||||
// touches lower boundary
|
||||
assertTrue(intRange.overlapsWith(Range.between(10, 19)));
|
||||
assertTrue(intRange.overlapsWith(Range.between(10, 21)));
|
||||
assertTrue(intRange.isOverlappedBy(Range.between(10, 19)));
|
||||
assertTrue(intRange.isOverlappedBy(Range.between(10, 21)));
|
||||
|
||||
// touches upper boundary
|
||||
assertTrue(intRange.overlapsWith(Range.between(11, 20)));
|
||||
assertTrue(intRange.overlapsWith(Range.between(9, 20)));
|
||||
assertTrue(intRange.isOverlappedBy(Range.between(11, 20)));
|
||||
assertTrue(intRange.isOverlappedBy(Range.between(9, 20)));
|
||||
|
||||
// negative
|
||||
assertFalse(intRange.overlapsWith(Range.between(-11, -18)));
|
||||
|
||||
assertFalse(intRange.isOverlappedBy(Range.between(-11, -18)));
|
||||
}
|
||||
|
||||
public void testIsBeforeRange() {
|
||||
assertFalse(intRange.isBeforeRange(null));
|
||||
|
||||
assertFalse(intRange.isBeforeRange(Range.between(5, 9)));
|
||||
|
||||
assertFalse(intRange.isBeforeRange(Range.between(5, 10)));
|
||||
assertFalse(intRange.isBeforeRange(Range.between(5, 20)));
|
||||
assertFalse(intRange.isBeforeRange(Range.between(5, 25)));
|
||||
assertFalse(intRange.isBeforeRange(Range.between(15, 25)));
|
||||
|
||||
assertTrue(intRange.isBeforeRange(Range.between(21, 25)));
|
||||
|
||||
assertFalse(intRange.isBeforeRange(Range.between(10, 20)));
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
public void testSerializing() {
|
||||
SerializationUtils.clone(intRange);
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user