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.