src/share/classes/java/lang/Long.java
Print this page
rev 10062 : 8041972: Add improved parse/format methods for Long/Integer
Contributed-by: redestad
*** 24,33 ****
--- 24,34 ----
*/
package java.lang;
import java.lang.annotation.Native;
+ import static java.lang.Integer.requireNonEmpty;
import java.math.*;
/**
* The {@code Long} class wraps a value of the primitive type {@code
*** 544,559 ****
* the specified radix.
* @throws NumberFormatException if the string does not contain a
* parsable {@code long}.
*/
public static long parseLong(String s, int radix)
! throws NumberFormatException
! {
! if (s == null) {
! throw new NumberFormatException("null");
}
if (radix < Character.MIN_RADIX) {
throw new NumberFormatException("radix " + radix +
" less than Character.MIN_RADIX");
}
if (radix > Character.MAX_RADIX) {
--- 545,624 ----
* the specified radix.
* @throws NumberFormatException if the string does not contain a
* parsable {@code long}.
*/
public static long parseLong(String s, int radix)
! throws NumberFormatException {
! requireNonEmpty(s);
! return parseLong(s, radix, 0, s.length());
! }
!
! /**
! * Parses the {@link CharSequence} argument as a signed {@code long} in
! * the specified {@code radix}, beginning at the specified {@code beginIndex}
! * and extending to the end of the sequence.
! *
! * <p>The method does not take steps to guard against the
! * {@code CharSequence} being mutated while parsing.
! *
! * @param s the {@code CharSequence} containing the {@code long}
! * representation to be parsed
! * @param radix the radix to be used while parsing {@code s}.
! * @param beginIndex the beginning index, inclusive.
! * @return the signed {@code long} represented by the subsequence in
! * the specified radix.
! * @throws NullPointerException if {@code s} is null.
! * @throws IllegalArgumentException if {@code beginIndex} is greater
! * than or equal to {@code s.length()}.
! * @throws IndexOutOfBoundsException if {@code beginIndex} is negative.
! * @throws NumberFormatException if the {@code CharSequence} does not
! * contain a parsable {@code long} in the specified
! * {@code radix}, or if {@code radix} is either smaller than
! * {@link java.lang.Character#MIN_RADIX} or larger than
! * {@link java.lang.Character#MAX_RADIX}.
! * @since 1.9
! */
! public static long parseLong(CharSequence s, int radix, int beginIndex)
! throws NumberFormatException {
! // forces a null check of s
! return parseLong(s, radix, beginIndex, s.length());
}
+ /**
+ * Parses the {@link CharSequence} argument as a signed {@code long} in
+ * the specified {@code radix}, beginning at the specified
+ * {@code beginIndex} and extending to {@code endIndex - 1}.
+ *
+ * <p>The method does not take steps to guard against the
+ * {@code CharSequence} being mutated while parsing.
+ *
+ * @param s the {@code CharSequence} containing the {@code long}
+ * representation to be parsed
+ * @param radix the radix to be used while parsing {@code s}.
+ * @param beginIndex the beginning index, inclusive.
+ * @param endIndex the ending index, exclusive.
+ * @return the signed {@code long} represented by the subsequence in
+ * the specified radix.
+ * @throws NullPointerException if {@code s} is null.
+ * @throws IllegalArgumentException if {@code beginIndex} is greater
+ * than or equal to {@code endIndex}.
+ * @throws IndexOutOfBoundsException if {@code beginIndex} is
+ * negative, {@code endIndex} is negative or {@code endIndex}
+ * is greater than {@code s.length()}
+ * @throws NumberFormatException if the {@code CharSequence} does not
+ * contain a parsable {@code long} in the specified
+ * {@code radix}, or if {@code radix} is either smaller than
+ * {@link java.lang.Character#MIN_RADIX} or larger than
+ * {@link java.lang.Character#MAX_RADIX}.
+ * @since 1.9
+ */
+ public static long parseLong(CharSequence s, int radix, int beginIndex, int endIndex)
+ throws NumberFormatException {
+ s.getClass(); // null check
+ if (beginIndex >= endIndex) {
+ throw new IllegalArgumentException("beginIndex must be less than endIndex");
+ }
if (radix < Character.MIN_RADIX) {
throw new NumberFormatException("radix " + radix +
" less than Character.MIN_RADIX");
}
if (radix > Character.MAX_RADIX) {
*** 561,607 ****
" greater than Character.MAX_RADIX");
}
long result = 0;
boolean negative = false;
! int i = 0, len = s.length();
long limit = -Long.MAX_VALUE;
long multmin;
int digit;
! if (len > 0) {
! char firstChar = s.charAt(0);
if (firstChar < '0') { // Possible leading "+" or "-"
if (firstChar == '-') {
negative = true;
limit = Long.MIN_VALUE;
! } else if (firstChar != '+')
! throw NumberFormatException.forInputString(s);
!
! if (len == 1) // Cannot have lone "+" or "-"
! throw NumberFormatException.forInputString(s);
i++;
}
multmin = limit / radix;
! while (i < len) {
// Accumulating negatively avoids surprises near MAX_VALUE
! digit = Character.digit(s.charAt(i++),radix);
! if (digit < 0) {
! throw NumberFormatException.forInputString(s);
! }
! if (result < multmin) {
! throw NumberFormatException.forInputString(s);
}
result *= radix;
if (result < limit + digit) {
! throw NumberFormatException.forInputString(s);
}
result -= digit;
}
- } else {
- throw NumberFormatException.forInputString(s);
- }
return negative ? result : -result;
}
/**
* Parses the string argument as a signed decimal {@code long}.
--- 626,666 ----
" greater than Character.MAX_RADIX");
}
long result = 0;
boolean negative = false;
! int i = beginIndex, end = endIndex;
long limit = -Long.MAX_VALUE;
long multmin;
int digit;
! char firstChar = s.charAt(i);
if (firstChar < '0') { // Possible leading "+" or "-"
if (firstChar == '-') {
negative = true;
limit = Long.MIN_VALUE;
! } else if (firstChar != '+') {
! throw NumberFormatException.forInputString(s.toString());
! }
i++;
+ if (end == i) { // Cannot have lone "+" or "-"
+ throw NumberFormatException.forInputString(s.toString());
+ }
}
multmin = limit / radix;
! while (i < end) {
// Accumulating negatively avoids surprises near MAX_VALUE
! digit = Character.digit(s.charAt(i++), radix);
! if (digit < 0 || result < multmin) {
! throw NumberFormatException.forInputString(s.toString());
}
result *= radix;
if (result < limit + digit) {
! throw NumberFormatException.forInputString(s.toString());
}
result -= digit;
}
return negative ? result : -result;
}
/**
* Parses the string argument as a signed decimal {@code long}.
*** 626,636 ****
* decimal.
* @throws NumberFormatException if the string does not contain a
* parsable {@code long}.
*/
public static long parseLong(String s) throws NumberFormatException {
! return parseLong(s, 10);
}
/**
* Parses the string argument as an unsigned {@code long} in the
* radix specified by the second argument. An unsigned integer
--- 685,696 ----
* decimal.
* @throws NumberFormatException if the string does not contain a
* parsable {@code long}.
*/
public static long parseLong(String s) throws NumberFormatException {
! requireNonEmpty(s);
! return parseLong(s, 10, 0, s.length());
}
/**
* Parses the string argument as an unsigned {@code long} in the
* radix specified by the second argument. An unsigned integer
*** 674,705 ****
* does not contain a parsable {@code long}.
* @since 1.8
*/
public static long parseUnsignedLong(String s, int radix)
throws NumberFormatException {
! if (s == null) {
! throw new NumberFormatException("null");
}
! int len = s.length();
if (len > 0) {
! char firstChar = s.charAt(0);
if (firstChar == '-') {
! throw new
! NumberFormatException(String.format("Illegal leading minus sign " +
! "on unsigned string %s.", s));
} else {
if (len <= 12 || // Long.MAX_VALUE in Character.MAX_RADIX is 13 digits
(radix == 10 && len <= 18) ) { // Long.MAX_VALUE in base 10 is 19 digits
! return parseLong(s, radix);
}
! // No need for range checks on len due to testing above.
! long first = parseLong(s.substring(0, len - 1), radix);
! int second = Character.digit(s.charAt(len - 1), radix);
if (second < 0) {
! throw new NumberFormatException("Bad digit at end of " + s);
}
long result = first * radix + second;
/*
* Test leftmost bits of multiprecision extension of first*radix
--- 734,830 ----
* does not contain a parsable {@code long}.
* @since 1.8
*/
public static long parseUnsignedLong(String s, int radix)
throws NumberFormatException {
! requireNonEmpty(s);
! return parseUnsignedLong(s, radix, 0);
! }
!
! /**
! * Parses the {@link CharSequence} argument as an unsigned {@code long} in
! * the specified {@code radix}, beginning at the specified
! * {@code beginIndex} and extending to the end of the sequence.
! *
! * <p>The method does not take steps to guard against the
! * {@code CharSequence} being mutated while parsing.
! *
! * @param s the {@code CharSequence} containing the unsigned
! * {@code long} representation to be parsed
! * @param radix the radix to be used while parsing {@code s}.
! * @param beginIndex the beginning index, inclusive.
! * @return the unsigned {@code long} represented by the subsequence in
! * the specified radix.
! * @throws NullPointerException if {@code s} is null.
! * @throws IllegalArgumentException if {@code beginIndex} is greater
! * than or equal to {@code s.length()}.
! * @throws IndexOutOfBoundsException if {@code beginIndex} is negative.
! * @throws NumberFormatException if the {@code CharSequence} does not
! * contain a parsable unsigned {@code long} in the specified
! * {@code radix}, or if {@code radix} is either smaller than
! * {@link java.lang.Character#MIN_RADIX} or larger than
! * {@link java.lang.Character#MAX_RADIX}.
! * @since 1.9
! */
! public static long parseUnsignedLong(CharSequence s, int radix, int beginIndex)
! throws NumberFormatException {
! // forces a null check of s
! return parseUnsignedLong(s, radix, beginIndex, s.length());
}
! /**
! * Parses the {@link CharSequence} argument as an unsigned {@code long} in
! * the specified {@code radix}, beginning at the specified
! * {@code beginIndex} and extending to {@code endIndex - 1}.
! *
! * <p>The method does not take steps to guard against the
! * {@code CharSequence} being mutated while parsing.
! *
! * @param s the {@code CharSequence} containing the unsigned
! * {@code long} representation to be parsed
! * @param radix the radix to be used while parsing {@code s}.
! * @param beginIndex the beginning index, inclusive.
! * @param endIndex the ending index, exclusive.
! * @return the unsigned {@code long} represented by the subsequence in
! * the specified radix.
! * @throws NullPointerException if {@code s} is null.
! * @throws IllegalArgumentException if {@code beginIndex} is greater
! * than or equal to {@code endIndex}.
! * @throws IndexOutOfBoundsException if {@code beginIndex} is
! * negative, {@code endIndex} is negative or {@code endIndex}
! * is greater than {@code s.length()}
! * @throws NumberFormatException if the {@code CharSequence} does not
! * contain a parsable unsigned {@code long} in the specified
! * {@code radix}, or if {@code radix} is either smaller than
! * {@link java.lang.Character#MIN_RADIX} or larger than
! * {@link java.lang.Character#MAX_RADIX}.
! * @since 1.9
! */
! public static long parseUnsignedLong(CharSequence s, int radix, int beginIndex, int endIndex)
! throws NumberFormatException {
! s.getClass(); // null check
! if (beginIndex >= endIndex) {
! throw new IllegalArgumentException("beginIndex must be less than endIndex");
! }
! int start = beginIndex, len = endIndex - beginIndex;
if (len > 0) {
! char firstChar = s.charAt(start);
if (firstChar == '-') {
! throw new NumberFormatException(String.format("Illegal leading minus sign " +
! "on unsigned string %s.", s.subSequence(start, start + len)));
} else {
if (len <= 12 || // Long.MAX_VALUE in Character.MAX_RADIX is 13 digits
(radix == 10 && len <= 18) ) { // Long.MAX_VALUE in base 10 is 19 digits
! return parseLong(s, radix, start, start + len);
}
! // No need for range checks on end due to testing above.
! long first = parseLong(s, radix, start, start + len - 1);
! int second = Character.digit(s.charAt(start + len - 1), radix);
if (second < 0) {
! throw new NumberFormatException("Bad digit at end of " +
! s.subSequence(start, start + len));
}
long result = first * radix + second;
/*
* Test leftmost bits of multiprecision extension of first*radix
*** 752,767 ****
* upper bound is too small to overflow again after the
* signed long overflows to positive above 2^64 - 1. Hence
* result >= 0 implies overflow given C and D.
*/
throw new NumberFormatException(String.format("String value %s exceeds " +
! "range of unsigned long.", s));
}
return result;
}
} else {
! throw NumberFormatException.forInputString(s);
}
}
/**
* Parses the string argument as an unsigned decimal {@code long}. The
--- 877,892 ----
* upper bound is too small to overflow again after the
* signed long overflows to positive above 2^64 - 1. Hence
* result >= 0 implies overflow given C and D.
*/
throw new NumberFormatException(String.format("String value %s exceeds " +
! "range of unsigned long.", s.subSequence(start, start + len)));
}
return result;
}
} else {
! throw NumberFormatException.forInputString("");
}
}
/**
* Parses the string argument as an unsigned decimal {@code long}. The
*** 778,788 ****
* @throws NumberFormatException if the string does not contain a
* parsable unsigned integer.
* @since 1.8
*/
public static long parseUnsignedLong(String s) throws NumberFormatException {
! return parseUnsignedLong(s, 10);
}
/**
* Returns a {@code Long} object holding the value
* extracted from the specified {@code String} when parsed
--- 903,914 ----
* @throws NumberFormatException if the string does not contain a
* parsable unsigned integer.
* @since 1.8
*/
public static long parseUnsignedLong(String s) throws NumberFormatException {
! requireNonEmpty(s);
! return parseUnsignedLong(s, 10, 0, s.length());
}
/**
* Returns a {@code Long} object holding the value
* extracted from the specified {@code String} when parsed
*** 808,818 ****
* radix.
* @throws NumberFormatException If the {@code String} does not
* contain a parsable {@code long}.
*/
public static Long valueOf(String s, int radix) throws NumberFormatException {
! return Long.valueOf(parseLong(s, radix));
}
/**
* Returns a {@code Long} object holding the value
* of the specified {@code String}. The argument is
--- 934,945 ----
* radix.
* @throws NumberFormatException If the {@code String} does not
* contain a parsable {@code long}.
*/
public static Long valueOf(String s, int radix) throws NumberFormatException {
! requireNonEmpty(s);
! return Long.valueOf(parseLong(s, radix, 0, s.length()));
}
/**
* Returns a {@code Long} object holding the value
* of the specified {@code String}. The argument is
*** 833,845 ****
* @return a {@code Long} object holding the value
* represented by the string argument.
* @throws NumberFormatException If the string cannot be parsed
* as a {@code long}.
*/
! public static Long valueOf(String s) throws NumberFormatException
! {
! return Long.valueOf(parseLong(s, 10));
}
private static class LongCache {
private LongCache(){}
--- 960,972 ----
* @return a {@code Long} object holding the value
* represented by the string argument.
* @throws NumberFormatException If the string cannot be parsed
* as a {@code long}.
*/
! public static Long valueOf(String s) throws NumberFormatException {
! requireNonEmpty(s);
! return Long.valueOf(parseLong(s, 10, 0, s.length()));
}
private static class LongCache {
private LongCache(){}
*** 997,1007 ****
* @throws NumberFormatException if the {@code String} does not
* contain a parsable {@code long}.
* @see java.lang.Long#parseLong(java.lang.String, int)
*/
public Long(String s) throws NumberFormatException {
! this.value = parseLong(s, 10);
}
/**
* Returns the value of this {@code Long} as a {@code byte} after
* a narrowing primitive conversion.
--- 1124,1135 ----
* @throws NumberFormatException if the {@code String} does not
* contain a parsable {@code long}.
* @see java.lang.Long#parseLong(java.lang.String, int)
*/
public Long(String s) throws NumberFormatException {
! requireNonEmpty(s);
! this.value = parseLong(s, 10, 0, s.length());
}
/**
* Returns the value of this {@code Long} as a {@code byte} after
* a narrowing primitive conversion.