美文网首页
Guava | Ints

Guava | Ints

作者: 拾壹北 | 来源:发表于2017-03-02 20:53 被阅读0次

    com.google.common.primitives.Ints
    官方文档:Primitives

    Ints提供了一些静态工具方法,正如官方文档所说:
    These types cannot be used as objects or as type parameters to generic types, which means that many general-purpose utilities cannot be applied to them. Guava provides a number of these general-purpose utilities, ways of interfacing between primitive arrays and collection APIs, conversion from types to byte array representations, and support for unsigned behaviors on certain types.
    这些类型(Bytes
    , SignedBytes
    , UnsignedBytes
    ,Shorts
    ,Ints
    , UnsignedInteger
    , UnsignedInts
    ,Longs
    , UnsignedLong
    , UnsignedLongs
    ,Floats
    ,Doubles
    ,Chars
    ,Booleans
    )不能用作对象或者是类型参数,而是以静态方法的形式提供了一些使用的工具,包括:

    • 数组和集合类型之间的转换
    • 从类型到字节数组的转换
    • 某些情形的无符号行为

    所以Ints中除了定义了一系列静态工具方法和实行这些方法所需要的静态变量之外, 没有其他内容,所以我们的学习重点应该在这些工具方法的实现上。

    1、checkedCast方法

    /**
     * Returns the {@code int} value that is equal to {@code value}, if possible.
     *
     * @param value any value in the range of the {@code int} type
     * @return the {@code int} value that equals {@code value}
     * @throws IllegalArgumentException if {@code value} is greater than {@link Integer#MAX_VALUE} or
     *     less than {@link Integer#MIN_VALUE}
     */
    public static int checkedCast(long value) {
      int result = (int) value;
      if (result != value) {
        // don't use checkArgument here, to avoid boxing
        throw new IllegalArgumentException("Out of range: " + value);
      }
      return result;
    }
    

    进行类型转换:将long类型的输入参数转换为int类型的返回,前提是long类型的值没有超过int的可表示范围,这里有两个点需要关注:

    • (1)强制类型转换,通过比较值是不是和原值相等来判断是否转换成功;
    • (2)避免不必要的装箱(boxing)操作

    2、toByteArray方法

    将一个整形value转换为大端表示,以byte array返回,array中每个值有4位。

    /**
     * Returns a big-endian representation of {value} in a 4-element byte array; equivalent to
     * {@code ByteBuffer.allocate(4).putInt(value).array()}. 
     * For example, the input value
     * {@code 0x12131415} would yield the byte array {@code {0x12, 0x13, 0x14, 0x15}}.
     *
     * <p>If you need to convert and concatenate several values (possibly even of different types),
     * use a shared {@link java.nio.ByteBuffer} instance, or use
     * {@link com.google.common.io.ByteStreams#newDataOutput()} to get a growable buffer.
     */
    @GwtIncompatible // doesn't work
    public static byte[] toByteArray(int value) {
      return new byte[] {
        (byte) (value >> 24), (byte) (value >> 16), (byte) (value >> 8), (byte) value
      };
    }
    

    3、join方法

    将整形数组里的所有元素之间,用一个separator连接起来,返回连接后形成的String,实现也相对比较简单。

    /**
     * Returns a string containing the supplied {@code int} values separated by {@code separator}. For
     * example, {@code join("-", 1, 2, 3)} returns the string {@code "1-2-3"}.
     *
     * @param separator the text that should appear between consecutive values in the resulting string
     *     (but not at the start or end)
     * @param array an array of {@code int} values, possibly empty
     */
    public static String join(String separator, int... array) {
        checkNotNull(separator);
        if (array.length == 0) {
          return "";
        }
    
      // For pre-sizing a builder, just get the right order of magnitude
      StringBuilder builder = new StringBuilder(array.length * 5);
      builder.append(array[0]);
      for (int i = 1; i < array.length; i++) {
        builder.append(separator).append(array[i]);
      }
      return builder.toString();
    }
    
    • 重点在:用StringBuilder进行字符串拼接。

    4、asList方法

    这个方法比较有意思。它的功能是将给定的整形数组转换为List<Integer>,有以下几点需要关注:

    • 我预想这个方法的设计是:创建List,遍历数组,然后逐个装箱,将这个List返回即可。但是实际上并没有这么做,而是专门声明了一个内部类IntArrayAsList,这个类继承自List的抽象类AbstractList,通过构造方法参数将需要转换的array传入,同时实现了相关的List方法,如size()、isEmpty()、get(int index)等。
    /**
     * Returns a fixed-size list backed by the specified array, similar to
     * {@link Arrays#asList(Object[])}. The list supports {@link List#set(int, Object)}, but any
     * attempt to set a value to {@code null} will result in a {@link NullPointerException}.
     *
     * <p>The returned list maintains the values, but not the identities, of {@code Integer} objects
     * written to or read from it. For example, whether {@code list.get(0) == list.get(0)} is true for
     * the returned list is unspecified.
     *
     * @param backingArray the array to back the list
     * @return a list view of the array
     */
    public static List<Integer> asList(int... backingArray) {
            if (backingArray.length == 0) {
            return Collections.emptyList();
            }
            return new IntArrayAsList(backingArray);
            }
    
    // 内部类
    @GwtCompatible
    private static class IntArrayAsList extends AbstractList<Integer>
            implements RandomAccess, Serializable {
        final int[] array;
        final int start;
        final int end;
    
        IntArrayAsList(int[] array) {
            this(array, 0, array.length);
        }
    
        IntArrayAsList(int[] array, int start, int end) {
            this.array = array;
            this.start = start;
            this.end = end;
        }
    
        @Override
        public int size() {
            return end - start;
        }
    
        @Override
        public boolean isEmpty() {
            return false;
        }
    
        @Override
        public Integer get(int index) {
            checkElementIndex(index, size());
            return array[start + index];
        }
    
        @Override
        public boolean contains(Object target) {
            // Overridden to prevent a ton of boxing
            return (target instanceof Integer) && Ints.indexOf(array, (Integer) target, start, end) != -1;
        }
    
        @Override
        public int indexOf(Object target) {
            // Overridden to prevent a ton of boxing
            if (target instanceof Integer) {
                int i = Ints.indexOf(array, (Integer) target, start, end);
                if (i >= 0) {
                    return i - start;
                }
            }
            return -1;
        }
    
        @Override
        public int lastIndexOf(Object target) {
            // Overridden to prevent a ton of boxing
            if (target instanceof Integer) {
                int i = Ints.lastIndexOf(array, (Integer) target, start, end);
                if (i >= 0) {
                    return i - start;
                }
            }
            return -1;
        }
    
        @Override
        public Integer set(int index, Integer element) {
            checkElementIndex(index, size());
            int oldValue = array[start + index];
            // checkNotNull for GWT (do not optimize)
            array[start + index] = checkNotNull(element);
            return oldValue;
        }
    
        @Override
        public List<Integer> subList(int fromIndex, int toIndex) {
            int size = size();
            checkPositionIndexes(fromIndex, toIndex, size);
            if (fromIndex == toIndex) {
                return Collections.emptyList();
            }
            return new IntArrayAsList(array, start + fromIndex, start + toIndex);
        }
    
        @Override
        public boolean equals(@Nullable Object object) {
            if (object == this) {
                return true;
            }
            if (object instanceof IntArrayAsList) {
                IntArrayAsList that = (IntArrayAsList) object;
                int size = size();
                if (that.size() != size) {
                    return false;
                }
                for (int i = 0; i < size; i++) {
                    if (array[start + i] != that.array[that.start + i]) {
                        return false;
                    }
                }
                return true;
            }
            return super.equals(object);
        }
    
        @Override
        public int hashCode() {
            int result = 1;
            for (int i = start; i < end; i++) {
                result = 31 * result + Ints.hashCode(array[i]);
            }
            return result;
        }
    
        @Override
        public String toString() {
            StringBuilder builder = new StringBuilder(size() * 5);
            builder.append('[').append(array[start]);
            for (int i = start + 1; i < end; i++) {
                builder.append(", ").append(array[i]);
            }
            return builder.append(']').toString();
        }
    
        int[] toIntArray() {
            // Arrays.copyOfRange() is not available under GWT
            int size = size();
            int[] result = new int[size];
            System.arraycopy(array, start, result, 0, size);
            return result;
        }
    
        private static final long serialVersionUID = 0;
    }
    

    5、lexicographicalComparator方法

    lexicographicalComparator方法会返回一个比较器,按照一个特定的规则来比较两个整型数组的大小,我这里并不想重点研究这个比较规则,而是关注这个方法的实现过程中一个关于枚举的巧妙用法。

    /**
     * Returns a comparator that compares two {@code int} arrays <a
     * href="http://en.wikipedia.org/wiki/Lexicographical_order">lexicographically</a>. That is, it
     * compares, using {@link #compare(int, int)}), the first pair of values that follow any common
     * prefix, or when one array is a prefix of the other, treats the shorter array as the lesser. For
     * example, {@code [] < [1] < [1, 2] < [2]}.
     *
     * <p>The returned comparator is inconsistent with {@link Object#equals(Object)} (since arrays
     * support only identity equality), but it is consistent with {@link Arrays#equals(int[], int[])}.
     *
     * @since 2.0
     */
    public static Comparator<int[]> lexicographicalComparator() {
            return LexicographicalComparator.INSTANCE;
            }
    
    private enum LexicographicalComparator implements Comparator<int[]> {
        INSTANCE;
    
        @Override
        public int compare(int[] left, int[] right) {
            int minLength = Math.min(left.length, right.length);
            for (int i = 0; i < minLength; i++) {
                int result = Ints.compare(left[i], right[i]);
                if (result != 0) {
                    return result;
                }
            }
            return left.length - right.length;
        }
    
        @Override
        public String toString() {
            return "Ints.lexicographicalComparator()";
        }
    }
    
    • 枚举实现接口
      枚举LexicographicalComparator实现了Comparator接口,重写了compare和toString方法,通过这种方式返回了一个Comparator比较器INSTANCE。
      这种做法兴许有些花哨,不走寻常路,完全可以用普通方式来实现这个比较器,不过这里引出了关于枚举使用的tips:
        枚举类型可以存储附加的数据和方法
        枚举类型可通过接口来定义行为
        枚举类型的项行为可通过接口来访问,跟正常的 Java 类无异values() 方法可用来返回接口中的一个数组
      总而言之,你可以像使用普通 Java 类一样来使用枚举类型。
    个人感受:提供了很多花式工具方法,但是实际的需求场景不同,估计也很难被用到吧。

    相关文章

      网友评论

          本文标题:Guava | Ints

          本文链接:https://www.haomeiwen.com/subject/qumkgttx.html