Java/Collections Data Structure/Range — различия между версиями
Admin (обсуждение | вклад) м (1 версия) |
|
(нет различий)
|
Текущая версия на 10:25, 1 июня 2010
Содержание
- 1 Byte Range
- 2 Finds the value in the range (start,limit) of the largest element (rank) where the count of all smaller elements in that range is less than or equals target.
- 3 IntRange represents an inclusive range of ints.
- 4 LongRange represents an inclusive range of longs.
- 5 NumberRange represents an inclusive range of java.lang.Number objects of the same type.
- 6 Represents a range of Number objects.
- 7 Represents a sequence of integer values, either ascending or descending.
- 8 This constructs an Iterator over each day in a date range defined by a focus date and range style.
Byte Range
<source lang="java">
/*
* Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */
/**
* @version $Id: ByteRange.java 587751 2007-10-24 02:41:36Z vgritsenko $ */
final public class ByteRange {
private final long start; private final long end; public ByteRange(long start, long end) { this.start = start; this.end = end; } public ByteRange(String string) throws NumberFormatException { string = string.trim(); int dashPos = string.indexOf("-"); int length = string.length(); if (string.indexOf(",") != -1) { throw new NumberFormatException("Simple ByteRange String contains a comma."); } if (dashPos > 0) { this.start = Integer.parseInt(string.substring(0, dashPos)); } else { this.start = Long.MIN_VALUE; } if (dashPos < length - 1) { this.end = Integer.parseInt(string.substring(dashPos + 1, length)); } else { this.end = Long.MAX_VALUE; } if (this.start > this.end) { throw new NumberFormatException("Start value is greater than end value."); } } public long getStart() { return this.start; } public long getEnd() { return this.end; } public long length() { return this.end - this.start + 1; } public ByteRange intersection(ByteRange range) { if (range.end < this.start || this.end < range.start) { return null; } else { long start = (this.start > range.start) ? this.start : range.start; long end = (this.end < range.end) ? this.end : range.end; return new ByteRange(start, end); } }
public String toString() { return this.start + "-" + this.end; }
}
</source>
Finds the value in the range (start,limit) of the largest element (rank) where the count of all smaller elements in that range is less than or equals target.
<source lang="java">
/* Copyright (c) 2001-2009, The HSQL Development Group
* All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * Redistributions of source code must retain the above copyright notice, this * list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * Neither the name of the HSQL Development Group nor the names of its * contributors may be used to endorse or promote products derived from this * software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL HSQL DEVELOPMENT GROUP, HSQLDB.ORG, * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */
/**
* Collection of routines for counting the distribution of the values * in an int[] array. * * @author Fred Toussi (fredt@users dot sourceforge.net) * @version 1.7.2 * @since 1.7.2 */
public class ArrayCounter {
/** * Returns an int[] array of length segments containing the distribution * count of the elements in unsorted int[] array with values between min* and max (range). Values outside the min-max range are ignored
* * A usage example is determining the count of people of each age group * in a large int[] array containing the age of each person. Called with * (array, 16,0,79), it will return an int[16] with the first element * the count of people aged 0-4, the second element the count of those * aged 5-9, and so on. People above the age of 79 are excluded. If the * range is not a multiple of segments, the last segment will be cover a * smaller sub-range than the rest. * */ public static int[] countSegments(int[] array, int elements, int segments, int start, int limit) { int[] counts = new int[segments]; long interval = calcInterval(segments, start, limit); int index = 0; int element = 0; if (interval <= 0) { return counts; } for (int i = 0; i < elements; i++) { element = array[i]; if (element < start || element >= limit) { continue; } index = (int) ((element - start) / interval); counts[index]++; } return counts; } /** * With an unsorted int[] array and with target a positive integer in the * range (1,array.length), finds the value in the range (start,limit) of the * largest element (rank) where the count of all smaller elements in that * range is less than or equals target. Parameter margin indicates the * margin of error in target<p> * * In statistics, this can be used to calculate a median or quadrile value. * A usage example applied to an array of age values is to determine * the maximum age of a given number of people. With the example array * given in countSegments, rank(array, c, 6000, 18, 65, 0) will return an age * value between 18-64 (inclusive) and the count of all people aged between * 18 and the returned value(exclusive) will be less than or equal 6000. * */ public static int rank(int[] array, int elements, int target, int start, int limit, int margin) { final int segments = 256; int elementCount = 0; int currentLimit = limit; for (;;) { long interval = calcInterval(segments, start, currentLimit); int[] counts = countSegments(array, elements, segments, start, currentLimit); for (int i = 0; i < counts.length; i++) { if (elementCount + counts[i] < target) { elementCount += counts[i]; start += interval; } else { break; } } if (elementCount + margin >= target) { return start; } if (interval <= 1) { return start; } currentLimit = start + interval < limit ? (int) (start + interval) : limit; } } /** * Helper method to calculate the span of the sub-interval. Simply returns * the cieling of ((limit - start) / segments) and accounts for invalid * start and limit combinations. */ static long calcInterval(int segments, int start, int limit) { long range = limit - start; if (range < 0) { return 0; } int partSegment = (range % segments) == 0 ? 0 : 1; return (range / segments) + partSegment; } } </source>
IntRange represents an inclusive range of ints.
<source lang="java">
/*
* Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */
import java.io.Serializable; /**
* <p>IntRange
represents an inclusive range of int
s.
* * @author Stephen Colebourne * @since 2.0 * @version $Id: IntRange.java 594398 2007-11-13 02:43:10Z bayard $ */
public final class IntRange extends Range implements Serializable {
/** * Required for serialization support. * * @see java.io.Serializable */ private static final long serialVersionUID = 71849363892730L; /** * The minimum number in this range (inclusive). */ private final int min; /** * The maximum number in this range (inclusive). */ private final int max; /** * Cached output minObject (class is immutable). */ private transient Integer minObject = null; /** * Cached output maxObject (class is immutable). */ private transient Integer maxObject = null; /** * Cached output hashCode (class is immutable). */ private transient int hashCode = 0; /** * Cached output toString (class is immutable). */ private transient String toString = null; /***
Constructs a new IntRange
using the specified
* number as both the minimum and maximum in this range.
* * @param number the number to use for this range */ public IntRange(int number) { super(); this.min = number; this.max = number; } /***
Constructs a new IntRange
using the specified
* number as both the minimum and maximum in this range.
* * @param number the number to use for this range, must not be*null
* @throws IllegalArgumentException if the number isnull
*/ public IntRange(Number number) { super(); if (number == null) { throw new IllegalArgumentException("The number must not be null"); } this.min = number.intValue(); this.max = number.intValue(); if (number instanceof Integer) { this.minObject = (Integer) number; this.maxObject = (Integer) number; } } /**
Constructs a new IntRange
with the specified
* minimum and maximum numbers (both inclusive).
**
The arguments may be passed in the order (min,max) or (max,min). The * getMinimum and getMaximum methods will return the correct values.
* * @param number1 first number that defines the edge of the range, inclusive * @param number2 second number that defines the edge of the range, inclusive */ public IntRange(int number1, int number2) { super(); if (number2 < number1) { this.min = number2; this.max = number1; } else { this.min = number1; this.max = number2; } } /***
Constructs a new IntRange
with the specified
* minimum and maximum numbers (both inclusive).
**
The arguments may be passed in the order (min,max) or (max,min). The * getMinimum and getMaximum methods will return the correct values.
*
* @param number1 first number that defines the edge of the range, inclusive
* @param number2 second number that defines the edge of the range, inclusive
* @throws IllegalArgumentException if either number is null
*/
public IntRange(Number number1, Number number2) {
super();
if (number1 == null || number2 == null) {
throw new IllegalArgumentException("The numbers must not be null");
}
int number1val = number1.intValue();
int number2val = number2.intValue();
if (number2val < number1val) {
this.min = number2val;
this.max = number1val;
if (number2 instanceof Integer) {
this.minObject = (Integer) number2;
}
if (number1 instanceof Integer) {
this.maxObject = (Integer) number1;
}
} else {
this.min = number1val;
this.max = number2val;
if (number1 instanceof Integer) {
this.minObject = (Integer) number1;
}
if (number2 instanceof Integer) {
this.maxObject = (Integer) number2;
}
}
}
// Accessors
//--------------------------------------------------------------------
/**
* Returns the minimum number in this range.
* * @return the minimum number in this range */ public Number getMinimumNumber() { if (minObject == null) { minObject = new Integer(min); } return minObject; } /***
Gets the minimum number in this range as a long
.
* * @return the minimum number in this range */ public long getMinimumLong() { return min; } /***
Gets the minimum number in this range as a int
.
* * @return the minimum number in this range */ public int getMinimumInteger() { return min; } /***
Gets the minimum number in this range as a double
.
* * @return the minimum number in this range */ public double getMinimumDouble() { return min; } /***
Gets the minimum number in this range as a float
.
* * @return the minimum number in this range */ public float getMinimumFloat() { return min; } /***
Returns the maximum number in this range.
* * @return the maximum number in this range */ public Number getMaximumNumber() { if (maxObject == null) { maxObject = new Integer(max); } return maxObject; } /***
Gets the maximum number in this range as a long
.
* * @return the maximum number in this range */ public long getMaximumLong() { return max; } /***
Gets the maximum number in this range as a int
.
* * @return the maximum number in this range */ public int getMaximumInteger() { return max; } /***
Gets the maximum number in this range as a double
.
* * @return the maximum number in this range */ public double getMaximumDouble() { return max; } /***
Gets the maximum number in this range as a float
.
* * @return the maximum number in this range */ public float getMaximumFloat() { return max; } // Tests //-------------------------------------------------------------------- /***
Tests whether the specified number
occurs within
* this range using int
comparison.
**
null
is handled and returns false
.
* * @param number the number to test, may be*null
* @returntrue
if the specified number occurs within this range */ public boolean containsNumber(Number number) { if (number == null) { return false; } return containsInteger(number.intValue()); } /**
Tests whether the specified int
occurs within
* this range using int
comparison.
**
This implementation overrides the superclass for performance as it is * the most common case.
* * @param value the int to test * @return*true
if the specified number occurs within this * range byint
comparison */ public boolean containsInteger(int value) { return value >= min && value <= max; } // Range tests //-------------------------------------------------------------------- /**
Tests whether the specified range occurs entirely within this range
* using int
comparison.
**
null
is handled and returns false
.
* * @param range the range to test, may be*null
* @returntrue
if the specified range occurs entirely within this range * @throws IllegalArgumentException if the range is not of this type */ public boolean containsRange(Range range) { if (range == null) { return false; } return containsInteger(range.getMinimumInteger()) && containsInteger(range.getMaximumInteger()); } /**
Tests whether the specified range overlaps with this range
* using int
comparison.
**
null
is handled and returns false
.
* * @param range the range to test, may be*null
* @returntrue
if the specified range overlaps with this range */ public boolean overlapsRange(Range range) { if (range == null) { return false; } return range.containsInteger(min) || range.containsInteger(max) || containsInteger(range.getMinimumInteger()); } // Basics //-------------------------------------------------------------------- /**
Compares this range to another object to test if they are equal.
.**
To be equal, the class, minimum and maximum must be equal.
*
* @param obj the reference object with which to compare
* @return true
if this object is equal
*/
public boolean equals(Object obj) {
if (obj == this) {
return true;
}
if (obj instanceof IntRange == false) {
return false;
}
IntRange range = (IntRange) obj;
return min == range.min && max == range.max;
}
/**
* Gets a hashCode for the range.
* * @return a hash code value for this object */ public int hashCode() { if (hashCode == 0) { hashCode = 17; hashCode = 37 * hashCode + getClass().hashCode(); hashCode = 37 * hashCode + min; hashCode = 37 * hashCode + max; } return hashCode; } /***
Gets the range as a String
.
**
The format of the String is "Range[min,max]".
*
* @return the String
representation of this range
*/
public String toString() {
if (toString == null) {
StringBuffer buf = new StringBuffer(32);
buf.append("Range[");
buf.append(min);
buf.append(",");
buf.append(max);
buf.append("]");
toString = buf.toString();
}
return toString;
}
/**
* Returns an array containing all the integer values in the range.
*
* @return the int[]
representation of this range
* @since 2.4
*/
public int[] toArray() {
int[] array = new int[max - min + 1];
for (int i = 0; i < array.length; i++) {
array[i] = min + i;
}
return array;
}
} /*
* Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */
/**
*Range
represents a range of numbers of the same type.
**
Specific subclasses hold the range values as different types. Each * subclass should be immutable and {@link java.io.Serializable Serializable} * if possible.
* * @author Stephen Colebourne * @since 2.0 * @version $Id: Range.java 437554 2006-08-28 06:21:41Z bayard $ */
abstract class Range {
/***
Constructs a new range.
*/ public Range() { super(); } // Accessors //-------------------------------------------------------------------- /***
Gets the minimum number in this range.
* * @return the minimum number in this range */ public abstract Number getMinimumNumber(); /***
Gets the minimum number in this range as a long
.
**
This implementation uses the {@link #getMinimumNumber()} method. * Subclasses may be able to optimise this.
* * @return the minimum number in this range */ public long getMinimumLong() { return getMinimumNumber().longValue(); } /***
Gets the minimum number in this range as a int
.
**
This implementation uses the {@link #getMinimumNumber()} method. * Subclasses may be able to optimise this.
* * @return the minimum number in this range */ public int getMinimumInteger() { return getMinimumNumber().intValue(); } /***
Gets the minimum number in this range as a double
.
**
This implementation uses the {@link #getMinimumNumber()} method. * Subclasses may be able to optimise this.
* * @return the minimum number in this range */ public double getMinimumDouble() { return getMinimumNumber().doubleValue(); } /***
Gets the minimum number in this range as a float
.
**
This implementation uses the {@link #getMinimumNumber()} method. * Subclasses may be able to optimise this.
* * @return the minimum number in this range */ public float getMinimumFloat() { return getMinimumNumber().floatValue(); } /***
Gets the maximum number in this range.
* * @return the maximum number in this range */ public abstract Number getMaximumNumber(); /***
Gets the maximum number in this range as a long
.
**
This implementation uses the {@link #getMaximumNumber()} method. * Subclasses may be able to optimise this.
* * @return the maximum number in this range */ public long getMaximumLong() { return getMaximumNumber().longValue(); } /***
Gets the maximum number in this range as a int
.
**
This implementation uses the {@link #getMaximumNumber()} method. * Subclasses may be able to optimise this.
* * @return the maximum number in this range */ public int getMaximumInteger() { return getMaximumNumber().intValue(); } /***
Gets the maximum number in this range as a double
.
**
This implementation uses the {@link #getMaximumNumber()} method. * Subclasses may be able to optimise this.
* * @return the maximum number in this range */ public double getMaximumDouble() { return getMaximumNumber().doubleValue(); } /***
Gets the maximum number in this range as a float
.
**
This implementation uses the {@link #getMaximumNumber()} method. * Subclasses may be able to optimise this.
* * @return the maximum number in this range */ public float getMaximumFloat() { return getMaximumNumber().floatValue(); } // Include tests //-------------------------------------------------------------------- /***
Tests whether the specified Number
occurs within
* this range.
**
The exact comparison implementation varies by subclass. It is
* intended that an int
specific subclass will compare using
* int
comparison.
**
null
is handled and returns false
.
* * @param number the number to test, may be*null
* @returntrue
if the specified number occurs within this range * @throws IllegalArgumentException if theNumber
cannot be compared */ public abstract boolean containsNumber(Number number); /**
Tests whether the specified Number
occurs within
* this range using long
comparison..
**
null
is handled and returns false
.
**
This implementation forwards to the {@link #containsLong(long)} method.
* * @param value the long to test, may be*null
* @returntrue
if the specified number occurs within this * range bylong
comparison */ public boolean containsLong(Number value) { if (value == null) { return false; } return containsLong(value.longValue()); } /**
Tests whether the specified long
occurs within
* this range using long
comparison.
**
This implementation uses the {@link #getMinimumLong()} and * {@link #getMaximumLong()} methods and should be good for most uses.
* * @param value the long to test * @return*true
if the specified number occurs within this * range bylong
comparison */ public boolean containsLong(long value) { return value >= getMinimumLong() && value <= getMaximumLong(); } /**
Tests whether the specified Number
occurs within
* this range using int
comparison..
**
null
is handled and returns false
.
**
This implementation forwards to the {@link #containsInteger(int)} method.
* * @param value the integer to test, may be*null
* @returntrue
if the specified number occurs within this * range byint
comparison */ public boolean containsInteger(Number value) { if (value == null) { return false; } return containsInteger(value.intValue()); } /**
Tests whether the specified int
occurs within
* this range using int
comparison.
**
This implementation uses the {@link #getMinimumInteger()} and * {@link #getMaximumInteger()} methods and should be good for most uses.
* * @param value the int to test * @return*true
if the specified number occurs within this * range byint
comparison */ public boolean containsInteger(int value) { return value >= getMinimumInteger() && value <= getMaximumInteger(); } /**
Tests whether the specified Number
occurs within
* this range using double
comparison..
**
null
is handled and returns false
.
**
This implementation forwards to the {@link #containsDouble(double)} method.
* * @param value the double to test, may be*null
* @returntrue
if the specified number occurs within this * range bydouble
comparison */ public boolean containsDouble(Number value) { if (value == null) { return false; } return containsDouble(value.doubleValue()); } /**
Tests whether the specified double
occurs within
* this range using double
comparison.
**
This implementation uses the {@link #getMinimumDouble()} and * {@link #getMaximumDouble()} methods and should be good for most uses.
* * @param value the double to test * @return*true
if the specified number occurs within this * range bydouble
comparison */ public boolean containsDouble(double value) { int compareMin = compare(getMinimumDouble(), value); int compareMax = compare(getMaximumDouble(), value); return compareMin <= 0 && compareMax >= 0; } /**
Tests whether the specified Number
occurs within
* this range using float
comparison.
**
null
is handled and returns false
.
**
This implementation forwards to the {@link #containsFloat(float)} method.
* * @param value the float to test, may be*null
* @returntrue
if the specified number occurs within this * range byfloat
comparison */ public boolean containsFloat(Number value) { if (value == null) { return false; } return containsFloat(value.floatValue()); } /**
Tests whether the specified float
occurs within
* this range using float
comparison.
**
This implementation uses the {@link #getMinimumFloat()} and * {@link #getMaximumFloat()} methods and should be good for most uses.
* * @param value the float to test * @return*true
if the specified number occurs within this * range byfloat
comparison */ public boolean containsFloat(float value) { int compareMin = compare(getMinimumFloat(), value); int compareMax = compare(getMaximumFloat(), value); return compareMin <= 0 && compareMax >= 0; } // Range tests //-------------------------------------------------------------------- /**
Tests whether the specified range occurs entirely within this range.
**
The exact comparison implementation varies by subclass. It is
* intended that an int
specific subclass will compare using
* int
comparison.
**
null
is handled and returns false
.
**
This implementation uses the {@link #containsNumber(Number)} method. * Subclasses may be able to optimise this.
* * @param range the range to test, may be*null
* @returntrue
if the specified range occurs entirely within * this range; otherwise,false
* @throws IllegalArgumentException if theRange
cannot be compared */ public boolean containsRange(Range range) { if (range == null) { return false; } return containsNumber(range.getMinimumNumber()) && containsNumber(range.getMaximumNumber()); } /**
Tests whether the specified range overlaps with this range.
**
The exact comparison implementation varies by subclass. It is
* intended that an int
specific subclass will compare using
* int
comparison.
**
null
is handled and returns false
.
**
This implementation uses the {@link #containsNumber(Number)} and * {@link #containsRange(Range)} methods. * Subclasses may be able to optimise this.
* * @param range the range to test, may be*null
* @returntrue
if the specified range overlaps with this * range; otherwise,false
* @throws IllegalArgumentException if theRange
cannot be compared */ public boolean overlapsRange(Range range) { if (range == null) { return false; } return range.containsNumber(getMinimumNumber()) || range.containsNumber(getMaximumNumber()) || containsNumber(range.getMinimumNumber()); } // Basics //-------------------------------------------------------------------- /**
Compares this range to another object to test if they are equal.
.**
To be equal, the class, minimum and maximum must be equal.
**
This implementation uses the {@link #getMinimumNumber()} and * {@link #getMaximumNumber()} methods. * Subclasses may be able to optimise this.
*
* @param obj the reference object with which to compare
* @return true
if this object is equal
*/
public boolean equals(Object obj) {
if (obj == this) {
return true;
} else if (obj == null || obj.getClass() != getClass()) {
return false;
} else {
Range range = (Range) obj;
return getMinimumNumber().equals(range.getMinimumNumber()) &&
getMaximumNumber().equals(range.getMaximumNumber());
}
}
/**
* Gets a hashCode for the range.
**
This implementation uses the {@link #getMinimumNumber()} and * {@link #getMaximumNumber()} methods. * Subclasses may be able to optimise this.
* * @return a hash code value for this object */ public int hashCode() { int result = 17; result = 37 * result + getClass().hashCode(); result = 37 * result + getMinimumNumber().hashCode(); result = 37 * result + getMaximumNumber().hashCode(); return result; } /***
Gets the range as a String
.
**
The format of the String is "Range[min,max]".
**
This implementation uses the {@link #getMinimumNumber()} and * {@link #getMaximumNumber()} methods. * Subclasses may be able to optimise this.
*
* @return the String
representation of this range
*/
public String toString() {
StringBuffer buf = new StringBuffer(32);
buf.append("Range[");
buf.append(getMinimumNumber());
buf.append(",");
buf.append(getMaximumNumber());
buf.append("]");
return buf.toString();
}
/**
* Compares two doubles
for order.
**
This method is more comprehensive than the standard Java greater * than, less than and equals operators.
*-
*
- It returns
-1
if the first value is less than the second.
* - It returns
+1
if the first value is greater than the second.
* - It returns
0
if the values are equal.
*
**
* The ordering is as follows, largest to smallest: *
-
*
- NaN *
- Positive infinity *
- Maximum double *
- Normal positive numbers *
- +0.0 *
- -0.0 *
- Normal negative numbers *
- Minimum double (
-Double.MAX_VALUE
) * - Negative infinity *
**
Comparing NaN
with NaN
will
* return 0
.
* * @param lhs the first*double
* @param rhs the seconddouble
* @return-1
if lhs is less,+1
if greater, *0
if equal to rhs */ public static int compare(double lhs, double rhs) { if (lhs < rhs) { return -1; } if (lhs > rhs) { return +1; } // Need to compare bits to handle 0.0 == -0.0 being true // compare should put -0.0 < +0.0 // Two NaNs are also == for compare purposes // where NaN == NaN is false long lhsBits = Double.doubleToLongBits(lhs); long rhsBits = Double.doubleToLongBits(rhs); if (lhsBits == rhsBits) { return 0; } // Something exotic! A comparison to NaN or 0.0 vs -0.0 // Fortunately NaN"s long is > than everything else // Also negzeros bits < poszero // NAN: 9221120237041090560 // MAX: 9218868437227405311 // NEGZERO: -9223372036854775808 if (lhsBits < rhsBits) { return -1; } else { return +1; } } /**
Compares two floats for order.
**
This method is more comprehensive than the standard Java greater than, * less than and equals operators.
*-
*
- It returns
-1
if the first value is less than the second. * - It returns
+1
if the first value is greater than the second. * - It returns
0
if the values are equal. *
**
The ordering is as follows, largest to smallest: *
-
*
- NaN *
- Positive infinity *
- Maximum float *
- Normal positive numbers *
- +0.0 *
- -0.0 *
- Normal negative numbers *
- Minimum float (
-Float.MAX_VALUE
) * - Negative infinity *
* * <p>Comparing*NaN
withNaN
will return
0
.
* * @param lhs the firstfloat
* @param rhs the secondfloat
* @return-1
if lhs is less,+1
if greater, *0
if equal to rhs */ public static int compare(float lhs, float rhs) { if (lhs < rhs) { return -1; } if (lhs > rhs) { return +1; } //Need to compare bits to handle 0.0 == -0.0 being true // compare should put -0.0 < +0.0 // Two NaNs are also == for compare purposes // where NaN == NaN is false int lhsBits = Float.floatToIntBits(lhs); int rhsBits = Float.floatToIntBits(rhs); if (lhsBits == rhsBits) { return 0; } //Something exotic! A comparison to NaN or 0.0 vs -0.0 //Fortunately NaN"s int is > than everything else //Also negzeros bits < poszero //NAN: 2143289344 //MAX: 2139095039 //NEGZERO: -2147483648 if (lhsBits < rhsBits) { return -1; } else { return +1; } }
}
</source>
LongRange represents an inclusive range of longs.
<source lang="java">
/*
* Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */
import java.io.Serializable; /**
*LongRange
represents an inclusive range of long
s.
* * @author Stephen Colebourne * @since 2.0 * @version $Id: LongRange.java 594398 2007-11-13 02:43:10Z bayard $ */
public final class LongRange extends Range implements Serializable {
/** * Required for serialization support. * * @see java.io.Serializable */ private static final long serialVersionUID = 71849363892720L; /** * The minimum number in this range (inclusive). */ private final long min; /** * The maximum number in this range (inclusive). */ private final long max; /** * Cached output minObject (class is immutable). */ private transient Long minObject = null; /** * Cached output maxObject (class is immutable). */ private transient Long maxObject = null; /** * Cached output hashCode (class is immutable). */ private transient int hashCode = 0; /** * Cached output toString (class is immutable). */ private transient String toString = null; /***
Constructs a new LongRange
using the specified
* number as both the minimum and maximum in this range.
* * @param number the number to use for this range */ public LongRange(long number) { super(); this.min = number; this.max = number; } /***
Constructs a new LongRange
using the specified
* number as both the minimum and maximum in this range.
* * @param number the number to use for this range, must not * be*null
* @throws IllegalArgumentException if the number isnull
*/ public LongRange(Number number) { super(); if (number == null) { throw new IllegalArgumentException("The number must not be null"); } this.min = number.longValue(); this.max = number.longValue(); if (number instanceof Long) { this.minObject = (Long) number; this.maxObject = (Long) number; } } /**
Constructs a new LongRange
with the specified
* minimum and maximum numbers (both inclusive).
**
The arguments may be passed in the order (min,max) or (max,min). The * getMinimum and getMaximum methods will return the correct values.
* * @param number1 first number that defines the edge of the range, inclusive * @param number2 second number that defines the edge of the range, inclusive */ public LongRange(long number1, long number2) { super(); if (number2 < number1) { this.min = number2; this.max = number1; } else { this.min = number1; this.max = number2; } } /***
Constructs a new LongRange
with the specified
* minimum and maximum numbers (both inclusive).
**
The arguments may be passed in the order (min,max) or (max,min). The * getMinimum and getMaximum methods will return the correct values.
*
* @param number1 first number that defines the edge of the range, inclusive
* @param number2 second number that defines the edge of the range, inclusive
* @throws IllegalArgumentException if either number is null
*/
public LongRange(Number number1, Number number2) {
super();
if (number1 == null || number2 == null) {
throw new IllegalArgumentException("The numbers must not be null");
}
long number1val = number1.longValue();
long number2val = number2.longValue();
if (number2val < number1val) {
this.min = number2val;
this.max = number1val;
if (number2 instanceof Long) {
this.minObject = (Long) number2;
}
if (number1 instanceof Long) {
this.maxObject = (Long) number1;
}
} else {
this.min = number1val;
this.max = number2val;
if (number1 instanceof Long) {
this.minObject = (Long) number1;
}
if (number2 instanceof Long) {
this.maxObject = (Long) number2;
}
}
}
// Accessors
//--------------------------------------------------------------------
/**
* Returns the minimum number in this range.
* * @return the minimum number in this range */ public Number getMinimumNumber() { if (minObject == null) { minObject = new Long(min); } return minObject; } /***
Gets the minimum number in this range as a long
.
* * @return the minimum number in this range */ public long getMinimumLong() { return min; } /***
Gets the minimum number in this range as a int
.
**
This conversion can lose information for large values.
* * @return the minimum number in this range */ public int getMinimumInteger() { return (int) min; } /***
Gets the minimum number in this range as a double
.
**
This conversion can lose information for large values.
* * @return the minimum number in this range */ public double getMinimumDouble() { return min; } /***
Gets the minimum number in this range as a float
.
**
This conversion can lose information for large values.
* * @return the minimum number in this range */ public float getMinimumFloat() { return min; } /***
Returns the maximum number in this range.
* * @return the maximum number in this range */ public Number getMaximumNumber() { if (maxObject == null) { maxObject = new Long(max); } return maxObject; } /***
Gets the maximum number in this range as a long
.
* * @return the maximum number in this range */ public long getMaximumLong() { return max; } /***
Gets the maximum number in this range cast to an int
.
**
This conversion can lose information for large values.
*
* @return the maximum number in this range cast to an int
.
*/
public int getMaximumInteger() {
return (int) max;
}
/**
* Gets the maximum number in this range as a double
.
**
This conversion can lose information for large values.
*
* @return The maximum number in this range as a double
.
*/
public double getMaximumDouble() {
return max;
}
/**
* Gets the maximum number in this range as a float
.
**
This conversion can lose information for large values.
*
* @return The maximum number in this range as a float
.
*/
public float getMaximumFloat() {
return max;
}
// Tests
//--------------------------------------------------------------------
/**
* Tests whether the specified number
occurs within
* this range using long
comparison.
**
null
is handled and returns false
.
* * @param number the number to test, may be*null
* @returntrue
if the specified number occurs within this range */ public boolean containsNumber(Number number) { if (number == null) { return false; } return containsLong(number.longValue()); } /**
Tests whether the specified long
occurs within
* this range using long
comparison.
**
This implementation overrides the superclass for performance as it is * the most common case.
* * @param value the long to test * @return*true
if the specified number occurs within this * range bylong
comparison */ public boolean containsLong(long value) { return value >= min && value <= max; } // Range tests //-------------------------------------------------------------------- /**
Tests whether the specified range occurs entirely within this range
* using long
comparison.
**
null
is handled and returns false
.
* * @param range the range to test, may be*null
* @returntrue
if the specified range occurs entirely within this range * @throws IllegalArgumentException if the range is not of this type */ public boolean containsRange(Range range) { if (range == null) { return false; } return containsLong(range.getMinimumLong()) && containsLong(range.getMaximumLong()); } /**
Tests whether the specified range overlaps with this range
* using long
comparison.
**
null
is handled and returns false
.
* * @param range the range to test, may be*null
* @returntrue
if the specified range overlaps with this range */ public boolean overlapsRange(Range range) { if (range == null) { return false; } return range.containsLong(min) || range.containsLong(max) || containsLong(range.getMinimumLong()); } // Basics //-------------------------------------------------------------------- /**
Compares this range to another object to test if they are equal.
.**
To be equal, the class, minimum and maximum must be equal.
*
* @param obj the reference object with which to compare
* @return true
if this object is equal
*/
public boolean equals(Object obj) {
if (obj == this) {
return true;
}
if (obj instanceof LongRange == false) {
return false;
}
LongRange range = (LongRange) obj;
return min == range.min && max == range.max;
}
/**
* Gets a hashCode for the range.
* * @return a hash code value for this object */ public int hashCode() { if (hashCode == 0) { hashCode = 17; hashCode = 37 * hashCode + getClass().hashCode(); hashCode = 37 * hashCode + ((int) (min ^ (min >> 32))); hashCode = 37 * hashCode + ((int) (max ^ (max >> 32))); } return hashCode; } /***
Gets the range as a String
.
**
The format of the String is "Range[min,max]".
*
* @return the String
representation of this range
*/
public String toString() {
if (toString == null) {
StringBuffer buf = new StringBuffer(32);
buf.append("Range[");
buf.append(min);
buf.append(",");
buf.append(max);
buf.append("]");
toString = buf.toString();
}
return toString;
}
/**
* Returns an array containing all the long values in the range.
*
* @return the long[]
representation of this range
* @since 2.4
*/
public long[] toArray() {
long[] array = new long[(int)(max - min + 1L)];
for(int i = 0; i < array.length; i++) {
array[i] = min + i;
}
return array;
}
} /*
* Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */
/**
*Range
represents a range of numbers of the same type.
**
Specific subclasses hold the range values as different types. Each * subclass should be immutable and {@link java.io.Serializable Serializable} * if possible.
* * @author Stephen Colebourne * @since 2.0 * @version $Id: Range.java 437554 2006-08-28 06:21:41Z bayard $ */
abstract class Range {
/***
Constructs a new range.
*/ public Range() { super(); } // Accessors //-------------------------------------------------------------------- /***
Gets the minimum number in this range.
* * @return the minimum number in this range */ public abstract Number getMinimumNumber(); /***
Gets the minimum number in this range as a long
.
**
This implementation uses the {@link #getMinimumNumber()} method. * Subclasses may be able to optimise this.
* * @return the minimum number in this range */ public long getMinimumLong() { return getMinimumNumber().longValue(); } /***
Gets the minimum number in this range as a int
.
**
This implementation uses the {@link #getMinimumNumber()} method. * Subclasses may be able to optimise this.
* * @return the minimum number in this range */ public int getMinimumInteger() { return getMinimumNumber().intValue(); } /***
Gets the minimum number in this range as a double
.
**
This implementation uses the {@link #getMinimumNumber()} method. * Subclasses may be able to optimise this.
* * @return the minimum number in this range */ public double getMinimumDouble() { return getMinimumNumber().doubleValue(); } /***
Gets the minimum number in this range as a float
.
**
This implementation uses the {@link #getMinimumNumber()} method. * Subclasses may be able to optimise this.
* * @return the minimum number in this range */ public float getMinimumFloat() { return getMinimumNumber().floatValue(); } /***
Gets the maximum number in this range.
* * @return the maximum number in this range */ public abstract Number getMaximumNumber(); /***
Gets the maximum number in this range as a long
.
**
This implementation uses the {@link #getMaximumNumber()} method. * Subclasses may be able to optimise this.
* * @return the maximum number in this range */ public long getMaximumLong() { return getMaximumNumber().longValue(); } /***
Gets the maximum number in this range as a int
.
**
This implementation uses the {@link #getMaximumNumber()} method. * Subclasses may be able to optimise this.
* * @return the maximum number in this range */ public int getMaximumInteger() { return getMaximumNumber().intValue(); } /***
Gets the maximum number in this range as a double
.
**
This implementation uses the {@link #getMaximumNumber()} method. * Subclasses may be able to optimise this.
* * @return the maximum number in this range */ public double getMaximumDouble() { return getMaximumNumber().doubleValue(); } /***
Gets the maximum number in this range as a float
.
**
This implementation uses the {@link #getMaximumNumber()} method. * Subclasses may be able to optimise this.
* * @return the maximum number in this range */ public float getMaximumFloat() { return getMaximumNumber().floatValue(); } // Include tests //-------------------------------------------------------------------- /***
Tests whether the specified Number
occurs within
* this range.
**
The exact comparison implementation varies by subclass. It is
* intended that an int
specific subclass will compare using
* int
comparison.
**
null
is handled and returns false
.
* * @param number the number to test, may be*null
* @returntrue
if the specified number occurs within this range * @throws IllegalArgumentException if theNumber
cannot be compared */ public abstract boolean containsNumber(Number number); /**
Tests whether the specified Number
occurs within
* this range using long
comparison..
**
null
is handled and returns false
.
**
This implementation forwards to the {@link #containsLong(long)} method.
* * @param value the long to test, may be*null
* @returntrue
if the specified number occurs within this * range bylong
comparison */ public boolean containsLong(Number value) { if (value == null) { return false; } return containsLong(value.longValue()); } /**
Tests whether the specified long
occurs within
* this range using long
comparison.
**
This implementation uses the {@link #getMinimumLong()} and * {@link #getMaximumLong()} methods and should be good for most uses.
* * @param value the long to test * @return*true
if the specified number occurs within this * range bylong
comparison */ public boolean containsLong(long value) { return value >= getMinimumLong() && value <= getMaximumLong(); } /**
Tests whether the specified Number
occurs within
* this range using int
comparison..
**
null
is handled and returns false
.
**
This implementation forwards to the {@link #containsInteger(int)} method.
* * @param value the integer to test, may be*null
* @returntrue
if the specified number occurs within this * range byint
comparison */ public boolean containsInteger(Number value) { if (value == null) { return false; } return containsInteger(value.intValue()); } /**
Tests whether the specified int
occurs within
* this range using int
comparison.
**
This implementation uses the {@link #getMinimumInteger()} and * {@link #getMaximumInteger()} methods and should be good for most uses.
* * @param value the int to test * @return*true
if the specified number occurs within this * range byint
comparison */ public boolean containsInteger(int value) { return value >= getMinimumInteger() && value <= getMaximumInteger(); } /**
Tests whether the specified Number
occurs within
* this range using double
comparison..
**
null
is handled and returns false
.
**
This implementation forwards to the {@link #containsDouble(double)} method.
* * @param value the double to test, may be*null
* @returntrue
if the specified number occurs within this * range bydouble
comparison */ public boolean containsDouble(Number value) { if (value == null) { return false; } return containsDouble(value.doubleValue()); } /**
Tests whether the specified double
occurs within
* this range using double
comparison.
**
This implementation uses the {@link #getMinimumDouble()} and * {@link #getMaximumDouble()} methods and should be good for most uses.
* * @param value the double to test * @return*true
if the specified number occurs within this * range bydouble
comparison */ public boolean containsDouble(double value) { int compareMin = compare(getMinimumDouble(), value); int compareMax = compare(getMaximumDouble(), value); return compareMin <= 0 && compareMax >= 0; } /**
Tests whether the specified Number
occurs within
* this range using float
comparison.
**
null
is handled and returns false
.
**
This implementation forwards to the {@link #containsFloat(float)} method.
* * @param value the float to test, may be*null
* @returntrue
if the specified number occurs within this * range byfloat
comparison */ public boolean containsFloat(Number value) { if (value == null) { return false; } return containsFloat(value.floatValue()); } /**
Tests whether the specified float
occurs within
* this range using float
comparison.
**
This implementation uses the {@link #getMinimumFloat()} and * {@link #getMaximumFloat()} methods and should be good for most uses.
* * @param value the float to test * @return*true
if the specified number occurs within this * range byfloat
comparison */ public boolean containsFloat(float value) { int compareMin = compare(getMinimumFloat(), value); int compareMax = compare(getMaximumFloat(), value); return compareMin <= 0 && compareMax >= 0; } // Range tests //-------------------------------------------------------------------- /**
Tests whether the specified range occurs entirely within this range.
**
The exact comparison implementation varies by subclass. It is
* intended that an int
specific subclass will compare using
* int
comparison.
**
null
is handled and returns false
.
**
This implementation uses the {@link #containsNumber(Number)} method. * Subclasses may be able to optimise this.
* * @param range the range to test, may be*null
* @returntrue
if the specified range occurs entirely within * this range; otherwise,false
* @throws IllegalArgumentException if theRange
cannot be compared */ public boolean containsRange(Range range) { if (range == null) { return false; } return containsNumber(range.getMinimumNumber()) && containsNumber(range.getMaximumNumber()); } /**
Tests whether the specified range overlaps with this range.
**
The exact comparison implementation varies by subclass. It is
* intended that an int
specific subclass will compare using
* int
comparison.
**
null
is handled and returns false
.
**
This implementation uses the {@link #containsNumber(Number)} and * {@link #containsRange(Range)} methods. * Subclasses may be able to optimise this.
* * @param range the range to test, may be*null
* @returntrue
if the specified range overlaps with this * range; otherwise,false
* @throws IllegalArgumentException if theRange
cannot be compared */ public boolean overlapsRange(Range range) { if (range == null) { return false; } return range.containsNumber(getMinimumNumber()) || range.containsNumber(getMaximumNumber()) || containsNumber(range.getMinimumNumber()); } // Basics //-------------------------------------------------------------------- /**
Compares this range to another object to test if they are equal.
.**
To be equal, the class, minimum and maximum must be equal.
**
This implementation uses the {@link #getMinimumNumber()} and * {@link #getMaximumNumber()} methods. * Subclasses may be able to optimise this.
*
* @param obj the reference object with which to compare
* @return true
if this object is equal
*/
public boolean equals(Object obj) {
if (obj == this) {
return true;
} else if (obj == null || obj.getClass() != getClass()) {
return false;
} else {
Range range = (Range) obj;
return getMinimumNumber().equals(range.getMinimumNumber()) &&
getMaximumNumber().equals(range.getMaximumNumber());
}
}
/**
* Gets a hashCode for the range.
**
This implementation uses the {@link #getMinimumNumber()} and * {@link #getMaximumNumber()} methods. * Subclasses may be able to optimise this.
* * @return a hash code value for this object */ public int hashCode() { int result = 17; result = 37 * result + getClass().hashCode(); result = 37 * result + getMinimumNumber().hashCode(); result = 37 * result + getMaximumNumber().hashCode(); return result; } /***
Gets the range as a String
.
**
The format of the String is "Range[min,max]".
**
This implementation uses the {@link #getMinimumNumber()} and * {@link #getMaximumNumber()} methods. * Subclasses may be able to optimise this.
*
* @return the String
representation of this range
*/
public String toString() {
StringBuffer buf = new StringBuffer(32);
buf.append("Range[");
buf.append(getMinimumNumber());
buf.append(",");
buf.append(getMaximumNumber());
buf.append("]");
return buf.toString();
}
/**
* Compares two doubles
for order.
**
This method is more comprehensive than the standard Java greater * than, less than and equals operators.
*-
*
- It returns
-1
if the first value is less than the second.
* - It returns
+1
if the first value is greater than the second.
* - It returns
0
if the values are equal.
*
**
* The ordering is as follows, largest to smallest: *
-
*
- NaN *
- Positive infinity *
- Maximum double *
- Normal positive numbers *
- +0.0 *
- -0.0 *
- Normal negative numbers *
- Minimum double (
-Double.MAX_VALUE
) * - Negative infinity *
**
Comparing NaN
with NaN
will
* return 0
.
* * @param lhs the first*double
* @param rhs the seconddouble
* @return-1
if lhs is less,+1
if greater, *0
if equal to rhs */ public static int compare(double lhs, double rhs) { if (lhs < rhs) { return -1; } if (lhs > rhs) { return +1; } // Need to compare bits to handle 0.0 == -0.0 being true // compare should put -0.0 < +0.0 // Two NaNs are also == for compare purposes // where NaN == NaN is false long lhsBits = Double.doubleToLongBits(lhs); long rhsBits = Double.doubleToLongBits(rhs); if (lhsBits == rhsBits) { return 0; } // Something exotic! A comparison to NaN or 0.0 vs -0.0 // Fortunately NaN"s long is > than everything else // Also negzeros bits < poszero // NAN: 9221120237041090560 // MAX: 9218868437227405311 // NEGZERO: -9223372036854775808 if (lhsBits < rhsBits) { return -1; } else { return +1; } } /**
Compares two floats for order.
**
This method is more comprehensive than the standard Java greater than, * less than and equals operators.
*-
*
- It returns
-1
if the first value is less than the second. * - It returns
+1
if the first value is greater than the second. * - It returns
0
if the values are equal. *
**
The ordering is as follows, largest to smallest: *
-
*
- NaN *
- Positive infinity *
- Maximum float *
- Normal positive numbers *
- +0.0 *
- -0.0 *
- Normal negative numbers *
- Minimum float (
-Float.MAX_VALUE
) * - Negative infinity *
* * <p>Comparing*NaN
withNaN
will return
0
.
* * @param lhs the firstfloat
* @param rhs the secondfloat
* @return-1
if lhs is less,+1
if greater, *0
if equal to rhs */ public static int compare(float lhs, float rhs) { if (lhs < rhs) { return -1; } if (lhs > rhs) { return +1; } //Need to compare bits to handle 0.0 == -0.0 being true // compare should put -0.0 < +0.0 // Two NaNs are also == for compare purposes // where NaN == NaN is false int lhsBits = Float.floatToIntBits(lhs); int rhsBits = Float.floatToIntBits(rhs); if (lhsBits == rhsBits) { return 0; } //Something exotic! A comparison to NaN or 0.0 vs -0.0 //Fortunately NaN"s int is > than everything else //Also negzeros bits < poszero //NAN: 2143289344 //MAX: 2139095039 //NEGZERO: -2147483648 if (lhsBits < rhsBits) { return -1; } else { return +1; } }
}
</source>
NumberRange represents an inclusive range of java.lang.Number objects of the same type.
<source lang="java">
/*
* Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */
import java.io.Serializable; /**
*NumberRange
represents an inclusive range of
* {@link java.lang.Number} objects of the same type.
* * @author * @author Stephen Colebourne * @since 2.0 (previously in org.apache.rumons.lang) * @version $Id: NumberRange.java 437554 2006-08-28 06:21:41Z bayard $ */
public final class NumberRange extends Range implements Serializable {
/** * Required for serialization support. * * @see java.io.Serializable */ private static final long serialVersionUID = 71849363892710L; /** * The minimum number in this range. */ private final Number min; /** * The maximum number in this range. */ private final Number max; /** * Cached output hashCode (class is immutable). */ private transient int hashCode = 0; /** * Cached output toString (class is immutable). */ private transient String toString = null; /***
Constructs a new NumberRange
using the specified
* number as both the minimum and maximum in this range.
* * @param num the number to use for this range * @throws IllegalArgumentException if the number is*null
* @throws IllegalArgumentException if the number doesn"t implementComparable
* @throws IllegalArgumentException if the number isDouble.NaN
orFloat.NaN
*/ public NumberRange(Number num) { if (num == null) { throw new IllegalArgumentException("The number must not be null"); } if (num instanceof Comparable == false) { throw new IllegalArgumentException("The number must implement Comparable"); } if (num instanceof Double && ((Double) num).isNaN()) { throw new IllegalArgumentException("The number must not be NaN"); } if (num instanceof Float && ((Float) num).isNaN()) { throw new IllegalArgumentException("The number must not be NaN"); } this.min = num; this.max = num; } /**
Constructs a new NumberRange
with the specified
* minimum and maximum numbers (both inclusive).
**
The arguments may be passed in the order (min,max) or (max,min). The * {@link #getMinimumNumber()} and {@link #getMaximumNumber()} methods will return the * correct value.
**
This constructor is designed to be used with two Number
* objects of the same type. If two objects of different types are passed in,
* an exception is thrown.
* * @param num1 first number that defines the edge of the range, inclusive * @param num2 second number that defines the edge of the range, inclusive * @throws IllegalArgumentException if either number is*null
* @throws IllegalArgumentException if the numbers are of different types * @throws IllegalArgumentException if the numbers don"t implementComparable
*/ public NumberRange(Number num1, Number num2) { if (num1 == null || num2 == null) { throw new IllegalArgumentException("The numbers must not be null"); } if (num1.getClass() != num2.getClass()) { throw new IllegalArgumentException("The numbers must be of the same type"); } if (num1 instanceof Comparable == false) { throw new IllegalArgumentException("The numbers must implement Comparable"); } if (num1 instanceof Double) { if (((Double) num1).isNaN() || ((Double) num2).isNaN()) { throw new IllegalArgumentException("The number must not be NaN"); } } else if (num1 instanceof Float) { if (((Float) num1).isNaN() || ((Float) num2).isNaN()) { throw new IllegalArgumentException("The number must not be NaN"); } } int compare = ((Comparable) num1).rupareTo(num2); if (compare == 0) { this.min = num1; this.max = num1; } else if (compare > 0) { this.min = num2; this.max = num1; } else { this.min = num1; this.max = num2; } } // Accessors //-------------------------------------------------------------------- /**
Returns the minimum number in this range.
* * @return the minimum number in this range */ public Number getMinimumNumber() { return min; } /***
Returns the maximum number in this range.
* * @return the maximum number in this range */ public Number getMaximumNumber() { return max; } // Tests //-------------------------------------------------------------------- /***
Tests whether the specified number
occurs within
* this range.
**
null
is handled and returns false
.
* * @param number the number to test, may be*null
* @returntrue
if the specified number occurs within this range * @throws IllegalArgumentException if the number is of a different type to the range */ public boolean containsNumber(Number number) { if (number == null) { return false; } if (number.getClass() != min.getClass()) { throw new IllegalArgumentException("The number must be of the same type as the range numbers"); } int compareMin = ((Comparable) min).rupareTo(number); int compareMax = ((Comparable) max).rupareTo(number); return compareMin <= 0 && compareMax >= 0; } // Range tests //-------------------------------------------------------------------- // use Range implementations // Basics //-------------------------------------------------------------------- /**
Compares this range to another object to test if they are equal.
.**
To be equal, the class, minimum and maximum must be equal.
*
* @param obj the reference object with which to compare
* @return true
if this object is equal
*/
public boolean equals(Object obj) {
if (obj == this) {
return true;
}
if (obj instanceof NumberRange == false) {
return false;
}
NumberRange range = (NumberRange) obj;
return min.equals(range.min) && max.equals(range.max);
}
/**
* Gets a hashCode for the range.
* * @return a hash code value for this object */ public int hashCode() { if (hashCode == 0) { hashCode = 17; hashCode = 37 * hashCode + getClass().hashCode(); hashCode = 37 * hashCode + min.hashCode(); hashCode = 37 * hashCode + max.hashCode(); } return hashCode; } /***
Gets the range as a String
.
**
The format of the String is "Range[min,max]".
*
* @return the String
representation of this range
*/
public String toString() {
if (toString == null) {
StringBuffer buf = new StringBuffer(32);
buf.append("Range[");
buf.append(min);
buf.append(",");
buf.append(max);
buf.append("]");
toString = buf.toString();
}
return toString;
}
} /*
* Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */
/**
*Range
represents a range of numbers of the same type.
**
Specific subclasses hold the range values as different types. Each * subclass should be immutable and {@link java.io.Serializable Serializable} * if possible.
* * @author Stephen Colebourne * @since 2.0 * @version $Id: Range.java 437554 2006-08-28 06:21:41Z bayard $ */
abstract class Range {
/***
Constructs a new range.
*/ public Range() { super(); } // Accessors //-------------------------------------------------------------------- /***
Gets the minimum number in this range.
* * @return the minimum number in this range */ public abstract Number getMinimumNumber(); /***
Gets the minimum number in this range as a long
.
**
This implementation uses the {@link #getMinimumNumber()} method. * Subclasses may be able to optimise this.
* * @return the minimum number in this range */ public long getMinimumLong() { return getMinimumNumber().longValue(); } /***
Gets the minimum number in this range as a int
.
**
This implementation uses the {@link #getMinimumNumber()} method. * Subclasses may be able to optimise this.
* * @return the minimum number in this range */ public int getMinimumInteger() { return getMinimumNumber().intValue(); } /***
Gets the minimum number in this range as a double
.
**
This implementation uses the {@link #getMinimumNumber()} method. * Subclasses may be able to optimise this.
* * @return the minimum number in this range */ public double getMinimumDouble() { return getMinimumNumber().doubleValue(); } /***
Gets the minimum number in this range as a float
.
**
This implementation uses the {@link #getMinimumNumber()} method. * Subclasses may be able to optimise this.
* * @return the minimum number in this range */ public float getMinimumFloat() { return getMinimumNumber().floatValue(); } /***
Gets the maximum number in this range.
* * @return the maximum number in this range */ public abstract Number getMaximumNumber(); /***
Gets the maximum number in this range as a long
.
**
This implementation uses the {@link #getMaximumNumber()} method. * Subclasses may be able to optimise this.
* * @return the maximum number in this range */ public long getMaximumLong() { return getMaximumNumber().longValue(); } /***
Gets the maximum number in this range as a int
.
**
This implementation uses the {@link #getMaximumNumber()} method. * Subclasses may be able to optimise this.
* * @return the maximum number in this range */ public int getMaximumInteger() { return getMaximumNumber().intValue(); } /***
Gets the maximum number in this range as a double
.
**
This implementation uses the {@link #getMaximumNumber()} method. * Subclasses may be able to optimise this.
* * @return the maximum number in this range */ public double getMaximumDouble() { return getMaximumNumber().doubleValue(); } /***
Gets the maximum number in this range as a float
.
**
This implementation uses the {@link #getMaximumNumber()} method. * Subclasses may be able to optimise this.
* * @return the maximum number in this range */ public float getMaximumFloat() { return getMaximumNumber().floatValue(); } // Include tests //-------------------------------------------------------------------- /***
Tests whether the specified Number
occurs within
* this range.
**
The exact comparison implementation varies by subclass. It is
* intended that an int
specific subclass will compare using
* int
comparison.
**
null
is handled and returns false
.
* * @param number the number to test, may be*null
* @returntrue
if the specified number occurs within this range * @throws IllegalArgumentException if theNumber
cannot be compared */ public abstract boolean containsNumber(Number number); /**
Tests whether the specified Number
occurs within
* this range using long
comparison..
**
null
is handled and returns false
.
**
This implementation forwards to the {@link #containsLong(long)} method.
* * @param value the long to test, may be*null
* @returntrue
if the specified number occurs within this * range bylong
comparison */ public boolean containsLong(Number value) { if (value == null) { return false; } return containsLong(value.longValue()); } /**
Tests whether the specified long
occurs within
* this range using long
comparison.
**
This implementation uses the {@link #getMinimumLong()} and * {@link #getMaximumLong()} methods and should be good for most uses.
* * @param value the long to test * @return*true
if the specified number occurs within this * range bylong
comparison */ public boolean containsLong(long value) { return value >= getMinimumLong() && value <= getMaximumLong(); } /**
Tests whether the specified Number
occurs within
* this range using int
comparison..
**
null
is handled and returns false
.
**
This implementation forwards to the {@link #containsInteger(int)} method.
* * @param value the integer to test, may be*null
* @returntrue
if the specified number occurs within this * range byint
comparison */ public boolean containsInteger(Number value) { if (value == null) { return false; } return containsInteger(value.intValue()); } /**
Tests whether the specified int
occurs within
* this range using int
comparison.
**
This implementation uses the {@link #getMinimumInteger()} and * {@link #getMaximumInteger()} methods and should be good for most uses.
* * @param value the int to test * @return*true
if the specified number occurs within this * range byint
comparison */ public boolean containsInteger(int value) { return value >= getMinimumInteger() && value <= getMaximumInteger(); } /**
Tests whether the specified Number
occurs within
* this range using double
comparison..
**
null
is handled and returns false
.
**
This implementation forwards to the {@link #containsDouble(double)} method.
* * @param value the double to test, may be*null
* @returntrue
if the specified number occurs within this * range bydouble
comparison */ public boolean containsDouble(Number value) { if (value == null) { return false; } return containsDouble(value.doubleValue()); } /**
Tests whether the specified double
occurs within
* this range using double
comparison.
**
This implementation uses the {@link #getMinimumDouble()} and * {@link #getMaximumDouble()} methods and should be good for most uses.
* * @param value the double to test * @return*true
if the specified number occurs within this * range bydouble
comparison */ public boolean containsDouble(double value) { int compareMin = compare(getMinimumDouble(), value); int compareMax = compare(getMaximumDouble(), value); return compareMin <= 0 && compareMax >= 0; } /**
Tests whether the specified Number
occurs within
* this range using float
comparison.
**
null
is handled and returns false
.
**
This implementation forwards to the {@link #containsFloat(float)} method.
* * @param value the float to test, may be*null
* @returntrue
if the specified number occurs within this * range byfloat
comparison */ public boolean containsFloat(Number value) { if (value == null) { return false; } return containsFloat(value.floatValue()); } /**
Tests whether the specified float
occurs within
* this range using float
comparison.
**
This implementation uses the {@link #getMinimumFloat()} and * {@link #getMaximumFloat()} methods and should be good for most uses.
* * @param value the float to test * @return*true
if the specified number occurs within this * range byfloat
comparison */ public boolean containsFloat(float value) { int compareMin = compare(getMinimumFloat(), value); int compareMax = compare(getMaximumFloat(), value); return compareMin <= 0 && compareMax >= 0; } // Range tests //-------------------------------------------------------------------- /**
Tests whether the specified range occurs entirely within this range.
**
The exact comparison implementation varies by subclass. It is
* intended that an int
specific subclass will compare using
* int
comparison.
**
null
is handled and returns false
.
**
This implementation uses the {@link #containsNumber(Number)} method. * Subclasses may be able to optimise this.
* * @param range the range to test, may be*null
* @returntrue
if the specified range occurs entirely within * this range; otherwise,false
* @throws IllegalArgumentException if theRange
cannot be compared */ public boolean containsRange(Range range) { if (range == null) { return false; } return containsNumber(range.getMinimumNumber()) && containsNumber(range.getMaximumNumber()); } /**
Tests whether the specified range overlaps with this range.
**
The exact comparison implementation varies by subclass. It is
* intended that an int
specific subclass will compare using
* int
comparison.
**
null
is handled and returns false
.
**
This implementation uses the {@link #containsNumber(Number)} and * {@link #containsRange(Range)} methods. * Subclasses may be able to optimise this.
* * @param range the range to test, may be*null
* @returntrue
if the specified range overlaps with this * range; otherwise,false
* @throws IllegalArgumentException if theRange
cannot be compared */ public boolean overlapsRange(Range range) { if (range == null) { return false; } return range.containsNumber(getMinimumNumber()) || range.containsNumber(getMaximumNumber()) || containsNumber(range.getMinimumNumber()); } // Basics //-------------------------------------------------------------------- /**
Compares this range to another object to test if they are equal.
.**
To be equal, the class, minimum and maximum must be equal.
**
This implementation uses the {@link #getMinimumNumber()} and * {@link #getMaximumNumber()} methods. * Subclasses may be able to optimise this.
*
* @param obj the reference object with which to compare
* @return true
if this object is equal
*/
public boolean equals(Object obj) {
if (obj == this) {
return true;
} else if (obj == null || obj.getClass() != getClass()) {
return false;
} else {
Range range = (Range) obj;
return getMinimumNumber().equals(range.getMinimumNumber()) &&
getMaximumNumber().equals(range.getMaximumNumber());
}
}
/**
* Gets a hashCode for the range.
**
This implementation uses the {@link #getMinimumNumber()} and * {@link #getMaximumNumber()} methods. * Subclasses may be able to optimise this.
* * @return a hash code value for this object */ public int hashCode() { int result = 17; result = 37 * result + getClass().hashCode(); result = 37 * result + getMinimumNumber().hashCode(); result = 37 * result + getMaximumNumber().hashCode(); return result; } /***
Gets the range as a String
.
**
The format of the String is "Range[min,max]".
**
This implementation uses the {@link #getMinimumNumber()} and * {@link #getMaximumNumber()} methods. * Subclasses may be able to optimise this.
*
* @return the String
representation of this range
*/
public String toString() {
StringBuffer buf = new StringBuffer(32);
buf.append("Range[");
buf.append(getMinimumNumber());
buf.append(",");
buf.append(getMaximumNumber());
buf.append("]");
return buf.toString();
}
/**
* Compares two doubles
for order.
**
This method is more comprehensive than the standard Java greater * than, less than and equals operators.
*-
*
- It returns
-1
if the first value is less than the second.
* - It returns
+1
if the first value is greater than the second.
* - It returns
0
if the values are equal.
*
**
* The ordering is as follows, largest to smallest: *
-
*
- NaN *
- Positive infinity *
- Maximum double *
- Normal positive numbers *
- +0.0 *
- -0.0 *
- Normal negative numbers *
- Minimum double (
-Double.MAX_VALUE
) * - Negative infinity *
**
Comparing NaN
with NaN
will
* return 0
.
* * @param lhs the first*double
* @param rhs the seconddouble
* @return-1
if lhs is less,+1
if greater, *0
if equal to rhs */ public static int compare(double lhs, double rhs) { if (lhs < rhs) { return -1; } if (lhs > rhs) { return +1; } // Need to compare bits to handle 0.0 == -0.0 being true // compare should put -0.0 < +0.0 // Two NaNs are also == for compare purposes // where NaN == NaN is false long lhsBits = Double.doubleToLongBits(lhs); long rhsBits = Double.doubleToLongBits(rhs); if (lhsBits == rhsBits) { return 0; } // Something exotic! A comparison to NaN or 0.0 vs -0.0 // Fortunately NaN"s long is > than everything else // Also negzeros bits < poszero // NAN: 9221120237041090560 // MAX: 9218868437227405311 // NEGZERO: -9223372036854775808 if (lhsBits < rhsBits) { return -1; } else { return +1; } } /**
Compares two floats for order.
**
This method is more comprehensive than the standard Java greater than, * less than and equals operators.
*-
*
- It returns
-1
if the first value is less than the second. * - It returns
+1
if the first value is greater than the second. * - It returns
0
if the values are equal. *
**
The ordering is as follows, largest to smallest: *
-
*
- NaN *
- Positive infinity *
- Maximum float *
- Normal positive numbers *
- +0.0 *
- -0.0 *
- Normal negative numbers *
- Minimum float (
-Float.MAX_VALUE
) * - Negative infinity *
* * <p>Comparing*NaN
withNaN
will return
0
.
* * @param lhs the firstfloat
* @param rhs the secondfloat
* @return-1
if lhs is less,+1
if greater, *0
if equal to rhs */ public static int compare(float lhs, float rhs) { if (lhs < rhs) { return -1; } if (lhs > rhs) { return +1; } //Need to compare bits to handle 0.0 == -0.0 being true // compare should put -0.0 < +0.0 // Two NaNs are also == for compare purposes // where NaN == NaN is false int lhsBits = Float.floatToIntBits(lhs); int rhsBits = Float.floatToIntBits(rhs); if (lhsBits == rhsBits) { return 0; } //Something exotic! A comparison to NaN or 0.0 vs -0.0 //Fortunately NaN"s int is > than everything else //Also negzeros bits < poszero //NAN: 2143289344 //MAX: 2139095039 //NEGZERO: -2147483648 if (lhsBits < rhsBits) { return -1; } else { return +1; } }
}
</source>
Represents a range of Number objects.
<source lang="java">
/*
* Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */
/**
*Represents a range of {@link Number} objects.
**
This class uses double
comparisons. This means that it
* is unsuitable for dealing with large Long
, BigDecimal
* or BigInteger
numbers.
* * @author * @author Stephen Colebourne * @since 1.0 * @version $Revision: 437554 $ $Date: 2006-08-27 23:21:41 -0700 (Sun, 27 Aug 2006) $ * * */
public final class NumberRange {
/* The minimum number in this range. */ private final Number min; /* The maximum number in this range. */ private final Number max;
/***
Constructs a new NumberRange
using
* number
as both the minimum and maximum in
* this range.
*
* @param num the number to use for this range
* @throws NullPointerException if the number is null
*/
public NumberRange(Number num) {
if (num == null) {
throw new NullPointerException("The number must not be null");
}
this.min = num;
this.max = num;
}
/**
* Constructs a new NumberRange
with the specified
* minimum and maximum numbers.
**
If the maximum is less than the minimum, the range will be constructed * from the minimum value to the minimum value, not what you would expect!.
*
* @param min the minimum number in this range
* @param max the maximum number in this range
* @throws NullPointerException if either the minimum or maximum number is
* null
*/
public NumberRange(Number min, Number max) {
if (min == null) {
throw new NullPointerException("The minimum value must not be null");
} else if (max == null) {
throw new NullPointerException("The maximum value must not be null");
}
if (max.doubleValue() < min.doubleValue()) {
this.min = this.max = min;
} else {
this.min = min;
this.max = max;
}
}
/**
* Returns the minimum number in this range.
* * @return the minimum number in this range */ public Number getMinimum() { return min; } /***
Returns the maximum number in this range.
* * @return the maximum number in this range */ public Number getMaximum() { return max; } /***
Tests whether the specified number
occurs within
* this range using double
comparison.
* * @param number the number to test * @return*true
if the specified number occurs within this * range; otherwise,false
*/ public boolean includesNumber(Number number) { if (number == null) { return false; } else { return !(min.doubleValue() > number.doubleValue()) && !(max.doubleValue() < number.doubleValue()); } } /**
Tests whether the specified range occurs entirely within this
* range using double
comparison.
* * @param range the range to test * @return*true
if the specified range occurs entirely within * this range; otherwise,false
*/ public boolean includesRange(NumberRange range) { if (range == null) { return false; } else { return includesNumber(range.min) && includesNumber(range.max); } } /**
Tests whether the specified range overlaps with this range
* using double
comparison.
* * @param range the range to test * @return*true
if the specified range overlaps with this * range; otherwise,false
*/ public boolean overlaps(NumberRange range) { if (range == null) { return false; } else { return range.includesNumber(min) || range.includesNumber(max) || includesRange(range); } } /**
Indicates whether some other Object
is
* "equal" to this one.
* * @param obj the reference object with which to compare * @return*true
if this object is the same as the obj * argument;false
otherwise */ public boolean equals(Object obj) { if (obj == this) { return true; } else if (!(obj instanceof NumberRange)) { return false; } else { NumberRange range = (NumberRange)obj; return min.equals(range.min) && max.equals(range.max); } } /**
Returns a hash code value for this object.
* * @return a hash code value for this object */ public int hashCode() { int result = 17; result = 37 * result + min.hashCode(); result = 37 * result + max.hashCode(); return result; } /***
Returns the string representation of this range.
**
This string is the string representation of the minimum and * maximum numbers in the range, separated by a hyphen. If a number * is negative, then it is enclosed in parentheses.
* * @return the string representation of this range */ public String toString() { StringBuffer sb = new StringBuffer(); if (min.doubleValue() < 0) { sb.append("(") .append(min) .append(")"); } else { sb.append(min); } sb.append("-"); if (max.doubleValue() < 0) { sb.append("(") .append(max) .append(")"); } else { sb.append(max); } return sb.toString(); }
}
</source>
Represents a sequence of integer values, either ascending or descending.
<source lang="java">
// Copyright 2006 The Apache Software Foundation // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License.
import java.util.Iterator; /**
* Represents a sequence of integer values, either ascending or descending. The sequence is always inclusive (of the * finish value). */
public final class IntegerRange implements Iterable<Integer> {
private final int start; private final int finish; private class RangeIterator implements Iterator<Integer> { private final int increment; private int value = start; private boolean hasNext = true; RangeIterator() { increment = start < finish ? +1 : -1; } public boolean hasNext() { return hasNext; } public Integer next() { if (!hasNext) throw new IllegalStateException(); int result = value; hasNext = value != finish; value += increment; return result; } public void remove() { throw new UnsupportedOperationException(); } } public IntegerRange(final int start, final int finish) { this.start = start; this.finish = finish; } public int getFinish() { return finish; } public int getStart() { return start; } @Override public String toString() { return String.format("%d..%d", start, finish); } /** * The main puprose of a range object is to produce an Iterator. Since IntegerRange is iterable, it is useful with * the Tapestry Loop component, but also with the Java for loop! */ public Iterator<Integer> iterator() { return new RangeIterator(); } @Override public int hashCode() { final int PRIME = 31; int result = PRIME + finish; result = PRIME * result + start; return result; } /** * Returns true if the other object is an IntegerRange with the same start and finish values. */ @Override public boolean equals(Object obj) { if (this == obj) return true; if (obj == null) return false; if (getClass() != obj.getClass()) return false; final IntegerRange other = (IntegerRange) obj; if (finish != other.finish) return false; return start == other.start; }
}
</source>
This constructs an Iterator over each day in a date range defined by a focus date and range style.
<source lang="java">
import java.util.Calendar; import java.util.Date; import java.util.Iterator; import java.util.TimeZone;
/**
* Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */
/**
A suite of utilities surrounding the use of the * {@link java.util.Calendar} and {@link java.util.Date} object.
**
DateUtils contains a lot of common methods considering manipulations * of Dates or Calendars. Some methods require some extra explanation. * The truncate and round methods could be considered the Math.floor(), * Math.ceil() or Math.round versions for dates * This way date-fields will be ignored in bottom-up order. * As a complement to these methods we"ve introduced some fragment-methods. * With these methods the Date-fields will be ignored in top-down order. * Since a date without a year is not a valid date, you have to decide in what * kind of date-field you want your result, for instance milliseconds or days. *
* * * * @author * @author Phil Steitz * @author Robert Scholte * @since 2.0 * @version $Id: DateUtils.java 634096 2008-03-06 00:58:11Z niallp $ */
public class Main {
/** * The UTC time zone (often referred to as GMT). */ public static final TimeZone UTC_TIME_ZONE = TimeZone.getTimeZone("GMT"); /** * Number of milliseconds in a standard second. * @since 2.1 */ public static final long MILLIS_PER_SECOND = 1000; /** * Number of milliseconds in a standard minute. * @since 2.1 */ public static final long MILLIS_PER_MINUTE = 60 * MILLIS_PER_SECOND; /** * Number of milliseconds in a standard hour. * @since 2.1 */ public static final long MILLIS_PER_HOUR = 60 * MILLIS_PER_MINUTE; /** * Number of milliseconds in a standard day. * @since 2.1 */ public static final long MILLIS_PER_DAY = 24 * MILLIS_PER_HOUR; /** * This is half a month, so this represents whether a date is in the top * or bottom half of the month. */ public final static int SEMI_MONTH = 1001; private static final int[][] fields = { {Calendar.MILLISECOND}, {Calendar.SECOND}, {Calendar.MINUTE}, {Calendar.HOUR_OF_DAY, Calendar.HOUR}, {Calendar.DATE, Calendar.DAY_OF_MONTH, Calendar.AM_PM /* Calendar.DAY_OF_YEAR, Calendar.DAY_OF_WEEK, Calendar.DAY_OF_WEEK_IN_MONTH */ }, {Calendar.MONTH, DateUtils.SEMI_MONTH}, {Calendar.YEAR}, {Calendar.ERA}}; /** * A week range, starting on Sunday. */ public final static int RANGE_WEEK_SUNDAY = 1; /** * A week range, starting on Monday. */ public final static int RANGE_WEEK_MONDAY = 2; /** * A week range, starting on the day focused. */ public final static int RANGE_WEEK_RELATIVE = 3; /** * A week range, centered around the day focused. */ public final static int RANGE_WEEK_CENTER = 4; /** * A month range, the week starting on Sunday. */ public final static int RANGE_MONTH_SUNDAY = 5; /** * A month range, the week starting on Monday. */ public final static int RANGE_MONTH_MONDAY = 6; //----------------------------------------------------------------------- /***
This constructs an Iterator
over each day in a date
* range defined by a focus date and range style.
**
For instance, passing Thursday, July 4, 2002 and a
* RANGE_MONTH_SUNDAY
will return an Iterator
* that starts with Sunday, June 30, 2002 and ends with Saturday, August 3,
* 2002, returning a Calendar instance for each intermediate day.
**
This method provides an iterator that returns Calendar objects. * The days are progressed using {@link Calendar#add(int, int)}.
*
* @param focus the date to work with, not null
* @param rangeStyle the style constant to use. Must be one of
* {@link DateUtils#RANGE_MONTH_SUNDAY},
* {@link DateUtils#RANGE_MONTH_MONDAY},
* {@link DateUtils#RANGE_WEEK_SUNDAY},
* {@link DateUtils#RANGE_WEEK_MONDAY},
* {@link DateUtils#RANGE_WEEK_RELATIVE},
* {@link DateUtils#RANGE_WEEK_CENTER}
* @return the date iterator, which always returns Calendar instances
* @throws IllegalArgumentException if the date is null
* @throws IllegalArgumentException if the rangeStyle is invalid
*/
public static Iterator iterator(Date focus, int rangeStyle) {
if (focus == null) {
throw new IllegalArgumentException("The date must not be null");
}
Calendar gval = Calendar.getInstance();
gval.setTime(focus);
return iterator(gval, rangeStyle);
}
/**
* This constructs an Iterator
over each day in a date
* range defined by a focus date and range style.
**
For instance, passing Thursday, July 4, 2002 and a
* RANGE_MONTH_SUNDAY
will return an Iterator
* that starts with Sunday, June 30, 2002 and ends with Saturday, August 3,
* 2002, returning a Calendar instance for each intermediate day.
**
This method provides an iterator that returns Calendar objects. * The days are progressed using {@link Calendar#add(int, int)}.
*
* @param focus the date to work with
* @param rangeStyle the style constant to use. Must be one of
* {@link DateUtils#RANGE_MONTH_SUNDAY},
* {@link DateUtils#RANGE_MONTH_MONDAY},
* {@link DateUtils#RANGE_WEEK_SUNDAY},
* {@link DateUtils#RANGE_WEEK_MONDAY},
* {@link DateUtils#RANGE_WEEK_RELATIVE},
* {@link DateUtils#RANGE_WEEK_CENTER}
* @return the date iterator
* @throws IllegalArgumentException if the date is null
* @throws IllegalArgumentException if the rangeStyle is invalid
*/
public static Iterator iterator(Calendar focus, int rangeStyle) {
if (focus == null) {
throw new IllegalArgumentException("The date must not be null");
}
Calendar start = null;
Calendar end = null;
int startCutoff = Calendar.SUNDAY;
int endCutoff = Calendar.SATURDAY;
switch (rangeStyle) {
case RANGE_MONTH_SUNDAY:
case RANGE_MONTH_MONDAY:
//Set start to the first of the month
start = truncate(focus, Calendar.MONTH);
//Set end to the last of the month
end = (Calendar) start.clone();
end.add(Calendar.MONTH, 1);
end.add(Calendar.DATE, -1);
//Loop start back to the previous sunday or monday
if (rangeStyle == RANGE_MONTH_MONDAY) {
startCutoff = Calendar.MONDAY;
endCutoff = Calendar.SUNDAY;
}
break;
case RANGE_WEEK_SUNDAY:
case RANGE_WEEK_MONDAY:
case RANGE_WEEK_RELATIVE:
case RANGE_WEEK_CENTER:
//Set start and end to the current date
start = truncate(focus, Calendar.DATE);
end = truncate(focus, Calendar.DATE);
switch (rangeStyle) {
case RANGE_WEEK_SUNDAY:
//already set by default
break;
case RANGE_WEEK_MONDAY:
startCutoff = Calendar.MONDAY;
endCutoff = Calendar.SUNDAY;
break;
case RANGE_WEEK_RELATIVE:
startCutoff = focus.get(Calendar.DAY_OF_WEEK);
endCutoff = startCutoff - 1;
break;
case RANGE_WEEK_CENTER:
startCutoff = focus.get(Calendar.DAY_OF_WEEK) - 3;
endCutoff = focus.get(Calendar.DAY_OF_WEEK) + 3;
break;
}
break;
default:
throw new IllegalArgumentException("The range style " + rangeStyle + " is not valid.");
}
if (startCutoff < Calendar.SUNDAY) {
startCutoff += 7;
}
if (startCutoff > Calendar.SATURDAY) {
startCutoff -= 7;
}
if (endCutoff < Calendar.SUNDAY) {
endCutoff += 7;
}
if (endCutoff > Calendar.SATURDAY) {
endCutoff -= 7;
}
while (start.get(Calendar.DAY_OF_WEEK) != startCutoff) {
start.add(Calendar.DATE, -1);
}
while (end.get(Calendar.DAY_OF_WEEK) != endCutoff) {
end.add(Calendar.DATE, 1);
}
return new DateIterator(start, end);
}
/**
* This constructs an Iterator
over each day in a date
* range defined by a focus date and range style.
**
For instance, passing Thursday, July 4, 2002 and a
* RANGE_MONTH_SUNDAY
will return an Iterator
* that starts with Sunday, June 30, 2002 and ends with Saturday, August 3,
* 2002, returning a Calendar instance for each intermediate day.
* * @param focus the date to work with, either **Date
orCalendar
* @param rangeStyle the style constant to use. Must be one of the range * styles listed for the {@link #iterator(Calendar, int)} method. * @return the date iterator * @throws IllegalArgumentException if the date * isnull
* @throws ClassCastException if the object type is * not aDate
orCalendar
*/ public static Iterator iterator(Object focus, int rangeStyle) { if (focus == null) { throw new IllegalArgumentException("The date must not be null"); } if (focus instanceof Date) { return iterator((Date) focus, rangeStyle); } else if (focus instanceof Calendar) { return iterator((Calendar) focus, rangeStyle); } else { throw new ClassCastException("Could not iterate based on " + focus); } } /**
Truncate this date, leaving the field specified as the most * significant field.
**
For example, if you had the datetime of 28 Mar 2002 * 13:45:01.231, if you passed with HOUR, it would return 28 Mar * 2002 13:00:00.000. If this was passed with MONTH, it would * return 1 Mar 2002 0:00:00.000.
* * @param date the date to work with, either*Date
* orCalendar
* @param field the field fromCalendar
* orSEMI_MONTH
* @return the rounded date * @throws IllegalArgumentException if the date * isnull
* @throws ClassCastException if the object type is not a *Date
orCalendar
* @throws ArithmeticException if the year is over 280 million */ public static Date truncate(Object date, int field) { if (date == null) { throw new IllegalArgumentException("The date must not be null"); } if (date instanceof Date) { return truncate((Date) date, field); } else if (date instanceof Calendar) { return truncate((Calendar) date, field).getTime(); } else { throw new ClassCastException("Could not truncate " + date); } } /**
Truncate this date, leaving the field specified as the most * significant field.
**
For example, if you had the datetime of 28 Mar 2002 * 13:45:01.231, if you passed with HOUR, it would return 28 Mar * 2002 13:00:00.000. If this was passed with MONTH, it would * return 1 Mar 2002 0:00:00.000.
* * @param date the date to work with * @param field the field from*Calendar
* orSEMI_MONTH
* @return the rounded date (a different object) * @throws IllegalArgumentException if the date isnull
* @throws ArithmeticException if the year is over 280 million */ public static Calendar truncate(Calendar date, int field) { if (date == null) { throw new IllegalArgumentException("The date must not be null"); } Calendar truncated = (Calendar) date.clone(); modify(truncated, field, false); return truncated; } //----------------------------------------------------------------------- /**
Internal calculation method.
* * @param val the calendar * @param field the field constant * @param round true to round, false to truncate * @throws ArithmeticException if the year is over 280 million */ private static void modify(Calendar val, int field, boolean round) { if (val.get(Calendar.YEAR) > 280000000) { throw new ArithmeticException("Calendar value too large for accurate calculations"); } if (field == Calendar.MILLISECOND) { return; } // ----------------- Fix for LANG-59 ---------------------- START --------------- // see http://issues.apache.org/jira/browse/LANG-59 // // Manually truncate milliseconds, seconds and minutes, rather than using // Calendar methods. Date date = val.getTime(); long time = date.getTime(); boolean done = false; // truncate milliseconds int millisecs = val.get(Calendar.MILLISECOND); if (!round || millisecs < 500) { time = time - millisecs; } if (field == Calendar.SECOND) { done = true; } // truncate seconds int seconds = val.get(Calendar.SECOND); if (!done && (!round || seconds < 30)) { time = time - (seconds * 1000L); } if (field == Calendar.MINUTE) { done = true; } // truncate minutes int minutes = val.get(Calendar.MINUTE); if (!done && (!round || minutes < 30)) { time = time - (minutes * 60000L); } // reset time if (date.getTime() != time) { date.setTime(time); val.setTime(date); } // ----------------- Fix for LANG-59 ----------------------- END ---------------- boolean roundUp = false; for (int i = 0; i < fields.length; i++) { for (int j = 0; j < fields[i].length; j++) { if (fields[i][j] == field) { //This is our field... we stop looping if (round && roundUp) { if (field == DateUtils.SEMI_MONTH) { //This is a special case that"s hard to generalize //If the date is 1, we round up to 16, otherwise // we subtract 15 days and add 1 month if (val.get(Calendar.DATE) == 1) { val.add(Calendar.DATE, 15); } else { val.add(Calendar.DATE, -15); val.add(Calendar.MONTH, 1); } } else { //We need at add one to this field since the // last number causes us to round up val.add(fields[i][0], 1); } } return; } } //We have various fields that are not easy roundings int offset = 0; boolean offsetSet = false; //These are special types of fields that require different rounding rules switch (field) { case DateUtils.SEMI_MONTH: if (fields[i][0] == Calendar.DATE) { //If we"re going to drop the DATE field"s value, // we want to do this our own way. //We need to subtrace 1 since the date has a minimum of 1 offset = val.get(Calendar.DATE) - 1; //If we"re above 15 days adjustment, that means we"re in the // bottom half of the month and should stay accordingly. if (offset >= 15) { offset -= 15; } //Record whether we"re in the top or bottom half of that range roundUp = offset > 7; offsetSet = true; } break; case Calendar.AM_PM: if (fields[i][0] == Calendar.HOUR_OF_DAY) { //If we"re going to drop the HOUR field"s value, // we want to do this our own way. offset = val.get(Calendar.HOUR_OF_DAY); if (offset >= 12) { offset -= 12; } roundUp = offset > 6; offsetSet = true; } break; } if (!offsetSet) { int min = val.getActualMinimum(fields[i][0]); int max = val.getActualMaximum(fields[i][0]); //Calculate the offset from the minimum allowed value offset = val.get(fields[i][0]) - min; //Set roundUp if this is more than half way between the minimum and maximum roundUp = offset > ((max - min) / 2); } //We need to remove this field if (offset != 0) { val.set(fields[i][0], val.get(fields[i][0]) - offset); } } throw new IllegalArgumentException("The field " + field + " is not supported"); } /***
Date iterator.
*/
static class DateIterator implements Iterator {
private final Calendar endFinal;
private final Calendar spot;
/**
* Constructs a DateIterator that ranges from one date to another.
*
* @param startFinal start date (inclusive)
* @param endFinal end date (not inclusive)
*/
DateIterator(Calendar startFinal, Calendar endFinal) {
super();
this.endFinal = endFinal;
spot = startFinal;
spot.add(Calendar.DATE, -1);
}
/**
* Has the iterator not reached the end date yet?
*
* @return true
if the iterator has yet to reach the end date
*/
public boolean hasNext() {
return spot.before(endFinal);
}
/**
* Return the next calendar in the iteration
*
* @return Object calendar for the next date
*/
public Object next() {
if (spot.equals(endFinal)) {
throw new RuntimeException();
}
spot.add(Calendar.DATE, 1);
return spot.clone();
}
/**
* Always throws UnsupportedOperationException.
*
* @throws UnsupportedOperationException
* @see java.util.Iterator#remove()
*/
public void remove() {
throw new UnsupportedOperationException();
}
}
}
</source>