001/*
002 * Copyright (C) 2008 The Guava Authors
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
005 * in compliance with the License. You may obtain a copy of the License at
006 *
007 * http://www.apache.org/licenses/LICENSE-2.0
008 *
009 * Unless required by applicable law or agreed to in writing, software distributed under the License
010 * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
011 * or implied. See the License for the specific language governing permissions and limitations under
012 * the License.
013 */
014
015package com.google.common.primitives;
016
017import static com.google.common.base.Preconditions.checkArgument;
018import static com.google.common.base.Preconditions.checkElementIndex;
019import static com.google.common.base.Preconditions.checkNotNull;
020import static com.google.common.base.Preconditions.checkPositionIndexes;
021
022import com.google.common.annotations.Beta;
023import com.google.common.annotations.GwtCompatible;
024import com.google.common.annotations.GwtIncompatible;
025import com.google.common.base.Converter;
026import java.io.Serializable;
027import java.util.AbstractList;
028import java.util.Arrays;
029import java.util.Collection;
030import java.util.Collections;
031import java.util.Comparator;
032import java.util.List;
033import java.util.RandomAccess;
034import org.checkerframework.checker.nullness.compatqual.NullableDecl;
035
036/**
037 * Static utility methods pertaining to {@code int} primitives, that are not already found in either
038 * {@link Integer} or {@link Arrays}.
039 *
040 * <p>See the Guava User Guide article on <a
041 * href="https://github.com/google/guava/wiki/PrimitivesExplained">primitive utilities</a>.
042 *
043 * @author Kevin Bourrillion
044 * @since 1.0
045 */
046@GwtCompatible(emulated = true)
047public final class Ints extends IntsMethodsForWeb {
048  private Ints() {}
049
050  /**
051   * The number of bytes required to represent a primitive {@code int} value.
052   *
053   * <p><b>Java 8 users:</b> use {@link Integer#BYTES} instead.
054   */
055  public static final int BYTES = Integer.SIZE / Byte.SIZE;
056
057  /**
058   * The largest power of two that can be represented as an {@code int}.
059   *
060   * @since 10.0
061   */
062  public static final int MAX_POWER_OF_TWO = 1 << (Integer.SIZE - 2);
063
064  /**
065   * Returns a hash code for {@code value}; equal to the result of invoking {@code ((Integer)
066   * value).hashCode()}.
067   *
068   * <p><b>Java 8 users:</b> use {@link Integer#hashCode(int)} instead.
069   *
070   * @param value a primitive {@code int} value
071   * @return a hash code for the value
072   */
073  public static int hashCode(int value) {
074    return value;
075  }
076
077  /**
078   * Returns the {@code int} value that is equal to {@code value}, if possible.
079   *
080   * @param value any value in the range of the {@code int} type
081   * @return the {@code int} value that equals {@code value}
082   * @throws IllegalArgumentException if {@code value} is greater than {@link Integer#MAX_VALUE} or
083   *     less than {@link Integer#MIN_VALUE}
084   */
085  public static int checkedCast(long value) {
086    int result = (int) value;
087    checkArgument(result == value, "Out of range: %s", value);
088    return result;
089  }
090
091  /**
092   * Returns the {@code int} nearest in value to {@code value}.
093   *
094   * @param value any {@code long} value
095   * @return the same value cast to {@code int} if it is in the range of the {@code int} type,
096   *     {@link Integer#MAX_VALUE} if it is too large, or {@link Integer#MIN_VALUE} if it is too
097   *     small
098   */
099  public static int saturatedCast(long value) {
100    if (value > Integer.MAX_VALUE) {
101      return Integer.MAX_VALUE;
102    }
103    if (value < Integer.MIN_VALUE) {
104      return Integer.MIN_VALUE;
105    }
106    return (int) value;
107  }
108
109  /**
110   * Compares the two specified {@code int} values. The sign of the value returned is the same as
111   * that of {@code ((Integer) a).compareTo(b)}.
112   *
113   * <p><b>Note for Java 7 and later:</b> this method should be treated as deprecated; use the
114   * equivalent {@link Integer#compare} method instead.
115   *
116   * @param a the first {@code int} to compare
117   * @param b the second {@code int} to compare
118   * @return a negative value if {@code a} is less than {@code b}; a positive value if {@code a} is
119   *     greater than {@code b}; or zero if they are equal
120   */
121  public static int compare(int a, int b) {
122    return (a < b) ? -1 : ((a > b) ? 1 : 0);
123  }
124
125  /**
126   * Returns {@code true} if {@code target} is present as an element anywhere in {@code array}.
127   *
128   * @param array an array of {@code int} values, possibly empty
129   * @param target a primitive {@code int} value
130   * @return {@code true} if {@code array[i] == target} for some value of {@code i}
131   */
132  public static boolean contains(int[] array, int target) {
133    for (int value : array) {
134      if (value == target) {
135        return true;
136      }
137    }
138    return false;
139  }
140
141  /**
142   * Returns the index of the first appearance of the value {@code target} in {@code array}.
143   *
144   * @param array an array of {@code int} values, possibly empty
145   * @param target a primitive {@code int} value
146   * @return the least index {@code i} for which {@code array[i] == target}, or {@code -1} if no
147   *     such index exists.
148   */
149  public static int indexOf(int[] array, int target) {
150    return indexOf(array, target, 0, array.length);
151  }
152
153  // TODO(kevinb): consider making this public
154  private static int indexOf(int[] array, int target, int start, int end) {
155    for (int i = start; i < end; i++) {
156      if (array[i] == target) {
157        return i;
158      }
159    }
160    return -1;
161  }
162
163  /**
164   * Returns the start position of the first occurrence of the specified {@code target} within
165   * {@code array}, or {@code -1} if there is no such occurrence.
166   *
167   * <p>More formally, returns the lowest index {@code i} such that {@code Arrays.copyOfRange(array,
168   * i, i + target.length)} contains exactly the same elements as {@code target}.
169   *
170   * @param array the array to search for the sequence {@code target}
171   * @param target the array to search for as a sub-sequence of {@code array}
172   */
173  public static int indexOf(int[] array, int[] target) {
174    checkNotNull(array, "array");
175    checkNotNull(target, "target");
176    if (target.length == 0) {
177      return 0;
178    }
179
180    outer:
181    for (int i = 0; i < array.length - target.length + 1; i++) {
182      for (int j = 0; j < target.length; j++) {
183        if (array[i + j] != target[j]) {
184          continue outer;
185        }
186      }
187      return i;
188    }
189    return -1;
190  }
191
192  /**
193   * Returns the index of the last appearance of the value {@code target} in {@code array}.
194   *
195   * @param array an array of {@code int} values, possibly empty
196   * @param target a primitive {@code int} value
197   * @return the greatest index {@code i} for which {@code array[i] == target}, or {@code -1} if no
198   *     such index exists.
199   */
200  public static int lastIndexOf(int[] array, int target) {
201    return lastIndexOf(array, target, 0, array.length);
202  }
203
204  // TODO(kevinb): consider making this public
205  private static int lastIndexOf(int[] array, int target, int start, int end) {
206    for (int i = end - 1; i >= start; i--) {
207      if (array[i] == target) {
208        return i;
209      }
210    }
211    return -1;
212  }
213
214  /**
215   * Returns the least value present in {@code array}.
216   *
217   * @param array a <i>nonempty</i> array of {@code int} values
218   * @return the value present in {@code array} that is less than or equal to every other value in
219   *     the array
220   * @throws IllegalArgumentException if {@code array} is empty
221   */
222  @GwtIncompatible(
223      "Available in GWT! Annotation is to avoid conflict with GWT specialization of base class.")
224  public static int min(int... array) {
225    checkArgument(array.length > 0);
226    int min = array[0];
227    for (int i = 1; i < array.length; i++) {
228      if (array[i] < min) {
229        min = array[i];
230      }
231    }
232    return min;
233  }
234
235  /**
236   * Returns the greatest value present in {@code array}.
237   *
238   * @param array a <i>nonempty</i> array of {@code int} values
239   * @return the value present in {@code array} that is greater than or equal to every other value
240   *     in the array
241   * @throws IllegalArgumentException if {@code array} is empty
242   */
243  @GwtIncompatible(
244      "Available in GWT! Annotation is to avoid conflict with GWT specialization of base class.")
245  public static int max(int... array) {
246    checkArgument(array.length > 0);
247    int max = array[0];
248    for (int i = 1; i < array.length; i++) {
249      if (array[i] > max) {
250        max = array[i];
251      }
252    }
253    return max;
254  }
255
256  /**
257   * Returns the value nearest to {@code value} which is within the closed range {@code [min..max]}.
258   *
259   * <p>If {@code value} is within the range {@code [min..max]}, {@code value} is returned
260   * unchanged. If {@code value} is less than {@code min}, {@code min} is returned, and if {@code
261   * value} is greater than {@code max}, {@code max} is returned.
262   *
263   * @param value the {@code int} value to constrain
264   * @param min the lower bound (inclusive) of the range to constrain {@code value} to
265   * @param max the upper bound (inclusive) of the range to constrain {@code value} to
266   * @throws IllegalArgumentException if {@code min > max}
267   * @since 21.0
268   */
269  @Beta
270  public static int constrainToRange(int value, int min, int max) {
271    checkArgument(min <= max, "min (%s) must be less than or equal to max (%s)", min, max);
272    return Math.min(Math.max(value, min), max);
273  }
274
275  /**
276   * Returns the values from each provided array combined into a single array. For example, {@code
277   * concat(new int[] {a, b}, new int[] {}, new int[] {c}} returns the array {@code {a, b, c}}.
278   *
279   * @param arrays zero or more {@code int} arrays
280   * @return a single array containing all the values from the source arrays, in order
281   */
282  public static int[] concat(int[]... arrays) {
283    int length = 0;
284    for (int[] array : arrays) {
285      length += array.length;
286    }
287    int[] result = new int[length];
288    int pos = 0;
289    for (int[] array : arrays) {
290      System.arraycopy(array, 0, result, pos, array.length);
291      pos += array.length;
292    }
293    return result;
294  }
295
296  /**
297   * Returns a big-endian representation of {@code value} in a 4-element byte array; equivalent to
298   * {@code ByteBuffer.allocate(4).putInt(value).array()}. For example, the input value {@code
299   * 0x12131415} would yield the byte array {@code {0x12, 0x13, 0x14, 0x15}}.
300   *
301   * <p>If you need to convert and concatenate several values (possibly even of different types),
302   * use a shared {@link java.nio.ByteBuffer} instance, or use {@link
303   * com.google.common.io.ByteStreams#newDataOutput()} to get a growable buffer.
304   */
305  public static byte[] toByteArray(int value) {
306    return new byte[] {
307      (byte) (value >> 24), (byte) (value >> 16), (byte) (value >> 8), (byte) value
308    };
309  }
310
311  /**
312   * Returns the {@code int} value whose big-endian representation is stored in the first 4 bytes of
313   * {@code bytes}; equivalent to {@code ByteBuffer.wrap(bytes).getInt()}. For example, the input
314   * byte array {@code {0x12, 0x13, 0x14, 0x15, 0x33}} would yield the {@code int} value {@code
315   * 0x12131415}.
316   *
317   * <p>Arguably, it's preferable to use {@link java.nio.ByteBuffer}; that library exposes much more
318   * flexibility at little cost in readability.
319   *
320   * @throws IllegalArgumentException if {@code bytes} has fewer than 4 elements
321   */
322  public static int fromByteArray(byte[] bytes) {
323    checkArgument(bytes.length >= BYTES, "array too small: %s < %s", bytes.length, BYTES);
324    return fromBytes(bytes[0], bytes[1], bytes[2], bytes[3]);
325  }
326
327  /**
328   * Returns the {@code int} value whose byte representation is the given 4 bytes, in big-endian
329   * order; equivalent to {@code Ints.fromByteArray(new byte[] {b1, b2, b3, b4})}.
330   *
331   * @since 7.0
332   */
333  public static int fromBytes(byte b1, byte b2, byte b3, byte b4) {
334    return b1 << 24 | (b2 & 0xFF) << 16 | (b3 & 0xFF) << 8 | (b4 & 0xFF);
335  }
336
337  private static final class IntConverter extends Converter<String, Integer>
338      implements Serializable {
339    static final IntConverter INSTANCE = new IntConverter();
340
341    @Override
342    protected Integer doForward(String value) {
343      return Integer.decode(value);
344    }
345
346    @Override
347    protected String doBackward(Integer value) {
348      return value.toString();
349    }
350
351    @Override
352    public String toString() {
353      return "Ints.stringConverter()";
354    }
355
356    private Object readResolve() {
357      return INSTANCE;
358    }
359
360    private static final long serialVersionUID = 1;
361  }
362
363  /**
364   * Returns a serializable converter object that converts between strings and integers using {@link
365   * Integer#decode} and {@link Integer#toString()}. The returned converter throws {@link
366   * NumberFormatException} if the input string is invalid.
367   *
368   * <p><b>Warning:</b> please see {@link Integer#decode} to understand exactly how strings are
369   * parsed. For example, the string {@code "0123"} is treated as <i>octal</i> and converted to the
370   * value {@code 83}.
371   *
372   * @since 16.0
373   */
374  @Beta
375  public static Converter<String, Integer> stringConverter() {
376    return IntConverter.INSTANCE;
377  }
378
379  /**
380   * Returns an array containing the same values as {@code array}, but guaranteed to be of a
381   * specified minimum length. If {@code array} already has a length of at least {@code minLength},
382   * it is returned directly. Otherwise, a new array of size {@code minLength + padding} is
383   * returned, containing the values of {@code array}, and zeroes in the remaining places.
384   *
385   * @param array the source array
386   * @param minLength the minimum length the returned array must guarantee
387   * @param padding an extra amount to "grow" the array by if growth is necessary
388   * @throws IllegalArgumentException if {@code minLength} or {@code padding} is negative
389   * @return an array containing the values of {@code array}, with guaranteed minimum length {@code
390   *     minLength}
391   */
392  public static int[] ensureCapacity(int[] array, int minLength, int padding) {
393    checkArgument(minLength >= 0, "Invalid minLength: %s", minLength);
394    checkArgument(padding >= 0, "Invalid padding: %s", padding);
395    return (array.length < minLength) ? Arrays.copyOf(array, minLength + padding) : array;
396  }
397
398  /**
399   * Returns a string containing the supplied {@code int} values separated by {@code separator}. For
400   * example, {@code join("-", 1, 2, 3)} returns the string {@code "1-2-3"}.
401   *
402   * @param separator the text that should appear between consecutive values in the resulting string
403   *     (but not at the start or end)
404   * @param array an array of {@code int} values, possibly empty
405   */
406  public static String join(String separator, int... array) {
407    checkNotNull(separator);
408    if (array.length == 0) {
409      return "";
410    }
411
412    // For pre-sizing a builder, just get the right order of magnitude
413    StringBuilder builder = new StringBuilder(array.length * 5);
414    builder.append(array[0]);
415    for (int i = 1; i < array.length; i++) {
416      builder.append(separator).append(array[i]);
417    }
418    return builder.toString();
419  }
420
421  /**
422   * Returns a comparator that compares two {@code int} arrays <a
423   * href="http://en.wikipedia.org/wiki/Lexicographical_order">lexicographically</a>. That is, it
424   * compares, using {@link #compare(int, int)}), the first pair of values that follow any common
425   * prefix, or when one array is a prefix of the other, treats the shorter array as the lesser. For
426   * example, {@code [] < [1] < [1, 2] < [2]}.
427   *
428   * <p>The returned comparator is inconsistent with {@link Object#equals(Object)} (since arrays
429   * support only identity equality), but it is consistent with {@link Arrays#equals(int[], int[])}.
430   *
431   * @since 2.0
432   */
433  public static Comparator<int[]> lexicographicalComparator() {
434    return LexicographicalComparator.INSTANCE;
435  }
436
437  private enum LexicographicalComparator implements Comparator<int[]> {
438    INSTANCE;
439
440    @Override
441    public int compare(int[] left, int[] right) {
442      int minLength = Math.min(left.length, right.length);
443      for (int i = 0; i < minLength; i++) {
444        int result = Ints.compare(left[i], right[i]);
445        if (result != 0) {
446          return result;
447        }
448      }
449      return left.length - right.length;
450    }
451
452    @Override
453    public String toString() {
454      return "Ints.lexicographicalComparator()";
455    }
456  }
457
458  /**
459   * Sorts the elements of {@code array} in descending order.
460   *
461   * @since 23.1
462   */
463  public static void sortDescending(int[] array) {
464    checkNotNull(array);
465    sortDescending(array, 0, array.length);
466  }
467
468  /**
469   * Sorts the elements of {@code array} between {@code fromIndex} inclusive and {@code toIndex}
470   * exclusive in descending order.
471   *
472   * @since 23.1
473   */
474  public static void sortDescending(int[] array, int fromIndex, int toIndex) {
475    checkNotNull(array);
476    checkPositionIndexes(fromIndex, toIndex, array.length);
477    Arrays.sort(array, fromIndex, toIndex);
478    reverse(array, fromIndex, toIndex);
479  }
480
481  /**
482   * Reverses the elements of {@code array}. This is equivalent to {@code
483   * Collections.reverse(Ints.asList(array))}, but is likely to be more efficient.
484   *
485   * @since 23.1
486   */
487  public static void reverse(int[] array) {
488    checkNotNull(array);
489    reverse(array, 0, array.length);
490  }
491
492  /**
493   * Reverses the elements of {@code array} between {@code fromIndex} inclusive and {@code toIndex}
494   * exclusive. This is equivalent to {@code
495   * Collections.reverse(Ints.asList(array).subList(fromIndex, toIndex))}, but is likely to be more
496   * efficient.
497   *
498   * @throws IndexOutOfBoundsException if {@code fromIndex < 0}, {@code toIndex > array.length}, or
499   *     {@code toIndex > fromIndex}
500   * @since 23.1
501   */
502  public static void reverse(int[] array, int fromIndex, int toIndex) {
503    checkNotNull(array);
504    checkPositionIndexes(fromIndex, toIndex, array.length);
505    for (int i = fromIndex, j = toIndex - 1; i < j; i++, j--) {
506      int tmp = array[i];
507      array[i] = array[j];
508      array[j] = tmp;
509    }
510  }
511
512  /**
513   * Returns an array containing each value of {@code collection}, converted to a {@code int} value
514   * in the manner of {@link Number#intValue}.
515   *
516   * <p>Elements are copied from the argument collection as if by {@code collection.toArray()}.
517   * Calling this method is as thread-safe as calling that method.
518   *
519   * @param collection a collection of {@code Number} instances
520   * @return an array containing the same values as {@code collection}, in the same order, converted
521   *     to primitives
522   * @throws NullPointerException if {@code collection} or any of its elements is null
523   * @since 1.0 (parameter was {@code Collection<Integer>} before 12.0)
524   */
525  public static int[] toArray(Collection<? extends Number> collection) {
526    if (collection instanceof IntArrayAsList) {
527      return ((IntArrayAsList) collection).toIntArray();
528    }
529
530    Object[] boxedArray = collection.toArray();
531    int len = boxedArray.length;
532    int[] array = new int[len];
533    for (int i = 0; i < len; i++) {
534      // checkNotNull for GWT (do not optimize)
535      array[i] = ((Number) checkNotNull(boxedArray[i])).intValue();
536    }
537    return array;
538  }
539
540  /**
541   * Returns a fixed-size list backed by the specified array, similar to {@link
542   * Arrays#asList(Object[])}. The list supports {@link List#set(int, Object)}, but any attempt to
543   * set a value to {@code null} will result in a {@link NullPointerException}.
544   *
545   * <p>The returned list maintains the values, but not the identities, of {@code Integer} objects
546   * written to or read from it. For example, whether {@code list.get(0) == list.get(0)} is true for
547   * the returned list is unspecified.
548   *
549   * <p><b>Note:</b> when possible, you should represent your data as an {@link ImmutableIntArray}
550   * instead, which has an {@link ImmutableIntArray#asList asList} view.
551   *
552   * @param backingArray the array to back the list
553   * @return a list view of the array
554   */
555  public static List<Integer> asList(int... backingArray) {
556    if (backingArray.length == 0) {
557      return Collections.emptyList();
558    }
559    return new IntArrayAsList(backingArray);
560  }
561
562  @GwtCompatible
563  private static class IntArrayAsList extends AbstractList<Integer>
564      implements RandomAccess, Serializable {
565    final int[] array;
566    final int start;
567    final int end;
568
569    IntArrayAsList(int[] array) {
570      this(array, 0, array.length);
571    }
572
573    IntArrayAsList(int[] array, int start, int end) {
574      this.array = array;
575      this.start = start;
576      this.end = end;
577    }
578
579    @Override
580    public int size() {
581      return end - start;
582    }
583
584    @Override
585    public boolean isEmpty() {
586      return false;
587    }
588
589    @Override
590    public Integer get(int index) {
591      checkElementIndex(index, size());
592      return array[start + index];
593    }
594
595    @Override
596    public boolean contains(Object target) {
597      // Overridden to prevent a ton of boxing
598      return (target instanceof Integer) && Ints.indexOf(array, (Integer) target, start, end) != -1;
599    }
600
601    @Override
602    public int indexOf(Object target) {
603      // Overridden to prevent a ton of boxing
604      if (target instanceof Integer) {
605        int i = Ints.indexOf(array, (Integer) target, start, end);
606        if (i >= 0) {
607          return i - start;
608        }
609      }
610      return -1;
611    }
612
613    @Override
614    public int lastIndexOf(Object target) {
615      // Overridden to prevent a ton of boxing
616      if (target instanceof Integer) {
617        int i = Ints.lastIndexOf(array, (Integer) target, start, end);
618        if (i >= 0) {
619          return i - start;
620        }
621      }
622      return -1;
623    }
624
625    @Override
626    public Integer set(int index, Integer element) {
627      checkElementIndex(index, size());
628      int oldValue = array[start + index];
629      // checkNotNull for GWT (do not optimize)
630      array[start + index] = checkNotNull(element);
631      return oldValue;
632    }
633
634    @Override
635    public List<Integer> subList(int fromIndex, int toIndex) {
636      int size = size();
637      checkPositionIndexes(fromIndex, toIndex, size);
638      if (fromIndex == toIndex) {
639        return Collections.emptyList();
640      }
641      return new IntArrayAsList(array, start + fromIndex, start + toIndex);
642    }
643
644    @Override
645    public boolean equals(@NullableDecl Object object) {
646      if (object == this) {
647        return true;
648      }
649      if (object instanceof IntArrayAsList) {
650        IntArrayAsList that = (IntArrayAsList) object;
651        int size = size();
652        if (that.size() != size) {
653          return false;
654        }
655        for (int i = 0; i < size; i++) {
656          if (array[start + i] != that.array[that.start + i]) {
657            return false;
658          }
659        }
660        return true;
661      }
662      return super.equals(object);
663    }
664
665    @Override
666    public int hashCode() {
667      int result = 1;
668      for (int i = start; i < end; i++) {
669        result = 31 * result + Ints.hashCode(array[i]);
670      }
671      return result;
672    }
673
674    @Override
675    public String toString() {
676      StringBuilder builder = new StringBuilder(size() * 5);
677      builder.append('[').append(array[start]);
678      for (int i = start + 1; i < end; i++) {
679        builder.append(", ").append(array[i]);
680      }
681      return builder.append(']').toString();
682    }
683
684    int[] toIntArray() {
685      return Arrays.copyOfRange(array, start, end);
686    }
687
688    private static final long serialVersionUID = 0;
689  }
690
691  /**
692   * Parses the specified string as a signed decimal integer value. The ASCII character {@code '-'}
693   * (<code>'&#92;u002D'</code>) is recognized as the minus sign.
694   *
695   * <p>Unlike {@link Integer#parseInt(String)}, this method returns {@code null} instead of
696   * throwing an exception if parsing fails. Additionally, this method only accepts ASCII digits,
697   * and returns {@code null} if non-ASCII digits are present in the string.
698   *
699   * <p>Note that strings prefixed with ASCII {@code '+'} are rejected, even under JDK 7, despite
700   * the change to {@link Integer#parseInt(String)} for that version.
701   *
702   * @param string the string representation of an integer value
703   * @return the integer value represented by {@code string}, or {@code null} if {@code string} has
704   *     a length of zero or cannot be parsed as an integer value
705   * @throws NullPointerException if {@code string} is {@code null}
706   * @since 11.0
707   */
708  @Beta
709  @NullableDecl
710  public static Integer tryParse(String string) {
711    return tryParse(string, 10);
712  }
713
714  /**
715   * Parses the specified string as a signed integer value using the specified radix. The ASCII
716   * character {@code '-'} (<code>'&#92;u002D'</code>) is recognized as the minus sign.
717   *
718   * <p>Unlike {@link Integer#parseInt(String, int)}, this method returns {@code null} instead of
719   * throwing an exception if parsing fails. Additionally, this method only accepts ASCII digits,
720   * and returns {@code null} if non-ASCII digits are present in the string.
721   *
722   * <p>Note that strings prefixed with ASCII {@code '+'} are rejected, even under JDK 7, despite
723   * the change to {@link Integer#parseInt(String, int)} for that version.
724   *
725   * @param string the string representation of an integer value
726   * @param radix the radix to use when parsing
727   * @return the integer value represented by {@code string} using {@code radix}, or {@code null} if
728   *     {@code string} has a length of zero or cannot be parsed as an integer value
729   * @throws IllegalArgumentException if {@code radix < Character.MIN_RADIX} or {@code radix >
730   *     Character.MAX_RADIX}
731   * @throws NullPointerException if {@code string} is {@code null}
732   * @since 19.0
733   */
734  @Beta
735  @NullableDecl
736  public static Integer tryParse(String string, int radix) {
737    Long result = Longs.tryParse(string, radix);
738    if (result == null || result.longValue() != result.intValue()) {
739      return null;
740    } else {
741      return result.intValue();
742    }
743  }
744}