ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

Google Guava 集合(Collections)

2019-09-07 12:02:31  阅读:224  来源: 互联网

标签:Map Google final Set static Collections Guava public Iterable


       这一篇文章我们来讲Google Guava集合,这是Guava最成熟和为人所知的部分。里面给我们提供各个集合的工具类,也给我们提供了一些新的集合类。

一 不可变集合

       不可变集合,顾名思义就是说集合是不可被修改的。集合的数据项是在创建的时候提供,并且在整个生命周期中都不可改变,一旦不可变集合创建之后,你是不可以对集合里面的做增,改操作的.我们为什么需要不可变集合,不可变集合的优势在哪里呢:

  • 对不可靠的客户代码库来说,它使用安全,可以在未受信任的类库中安全的使用这些对象.
  • 线程安全的:immutable对象在多线程下安全,没有竞态条件
  • 不可变集合不需要考虑变化,因此可以节省时间和空间。所有不可变的集合都比它们的可变形式有更好的内存利用率(分析和测试细节)
  • 不可变对象因为固定不变,可以作为常量来安全使用

       我们先看下Guava库里面给我们提供了哪些不可变集合,以及这些集合和JDK里面集合的关系.我们直接用表格形式列出,如下所示;

可变集合接口 属于JDK还是Guava 不可变版本
Collection JDK ImmutableCollection
List JDK ImmutableList
Set JDK ImmutableSet
SortedSet/NavigableSet JDK ImmutableSortedSet
Map JDK ImmutableMap
SortedMap JDK ImmutableSortedMap
Multiset Guava ImmutableMultiset
SortedMultiset Guava ImmutableSortedMultiset
Multimap Guava ImmutableMultimap
ListMultimap Guava ImmutableListMultimap
SetMultimap Guava ImmutableSetMultimap
BiMap Guava ImmutableBiMap
ClassToInstanceMap Guava ImmutableClassToInstanceMap
Table Guava ImmutableTable

1.1 不可变集合的使用

       Guava库里面不可变集合的使用主要在两个方面吧,一个是怎么创建不可变集合,另一个是怎么获取不可变集合里面的元素.关于怎么获取里面的元素,这个咱们不讲.和JDK里面使用集合是一样的.我们接下来要讲的主要在怎么去创建不可变集合.Guava库里面提供的每个不可变集合类都有如下三种方法.

如果你尝试去修改不可变集合会跑出UnsupportedOperationException异常.

  • 调用静态方法of创建.

       of()方法通过给定集合里面的元素来生成不可变集合.

        ImmutableList<String> imutableUserList = ImmutableList.of("jiangxi", "nanchang");
  • 调用静态方法copyOf创建.

       我们可以简单的理解为copyOf方法就是讲对应的JDK集合转换为Guava不可变集合.如果你想将List转换为不可变集合,就使用ImmutableList.copyOf(list)方法,如果想Set装换为不可变集合就调用ImmutableSet.copyOf(set),其他的不可变集合也是类似的.

        List<String> userList = new ArrayList<>();
        userList.add("jiangxi");
        userList.add("nanchang");
        ImmutableList<String> imutableUserList = ImmutableList.copyOf(userList);
  • 调用静态方法build创建.
        ImmutableList<String> imutableUserList = ImmutableList.<String>builder()
                .add("jiangxi")
                .add("nanchang")
                .build();

       Guava库里面每个不可变集合一般都有这三种方法来创建对应的不可变集合.当然了里面还有一些其他的方法,我们都可以到源码里面去看.都是很好理解的一些方法.

二 新集合类型

       Guava引入了很多JDK没有的(multisets, multimaps, tables, bidirectional maps等)、但我们发现明显有用的新集合类型。这些新类型是为了和JDK集合框架共存,而没有往JDK集合抽象中硬塞其他概念。作为一般规则,Guava集合非常精准地遵循了JDK接口契约。将白了就是和JDK里面集合的使用是差不多的.

2.1 Multiset

       Guava提供了一个新的Set类型Multiset,它可以多次添加相等的元素到Set里面去.Multiset有很多实现类.这个我们放下面讲.我们先看下Multiset里面的主要方法:

方法 描述
count(E) 给定元素在Multiset中的计数
elementSet() Multiset中不重复元素的集合,类型为Set
entrySet() 和Map的entrySet类似,返回Set<Multiset.Entry>,其中包含的Entry支持getElement()和getCount()方法
add(E, int) 增加给定元素在Multiset中的计数
remove(E, int) 减少给定元素在Multiset中的计数
setCount(E, int) 设置给定元素在Multiset中的计数,不可以为负数
size() 返回集合元素的总个数(包括重复的元素)

       Guava提供了多种Multiset的实现类,大部分都是和JDK中Set类一一对应的,有些也是Guava特有的.

Multiset实现类 JDK对应 内部实现
HashMultiset HashSet HashMap
TreeMultiset TreeSet TreeMap
LinkedHashMultiset LinkedHashSet LinkedHashMap
ConcurrentHashMultiset LinkedHashSet ConcurrentHashMap
ImmutableMultiset ImmutableMap
SortedMultiset SortedMultiset是Multiset 接口的变种,支持排序

2.3 Multimap

       每个有经验的Java程序员都在某处实现过Map<K, List>或Map<K, Set>,并且要忍受这个结构的笨拙。例如,Map<K, Set>通常用来表示非标定有向图。Guava的 Multimap可以很容易地把一个键映射到多个值。换句话说,Multimap是把键映射到任意多个值的一般方式。说白了就是一个key可以对应多个value.Multimap的使用和咱JDK里面Map的使用是类似的.

       Multimap的各种实现类.

Multimap实现类 键行为类似 行为类似
ArrayListMultimap HashMap ArrayList
HashMultimap HashMap HashSet
LinkedListMultimap* LinkedHashMap LinkedList*
LinkedHashMultimap** LinkedHashMap LinkedHashMap
TreeMultimap TreeMap TreeSet
ImmutableListMultimap ImmutableMap ImmutableList
mmutableSetMultimap ImmutableMap ImmutableSet

2.4 BiMap

       BiMap是特殊的Map.BiMap提供了一种新的集合类型,它提供了key和value的双向关联的数据结构。平常咱们用的最多的都是通过key获取value.但是反过来通过value获取key就比较复杂了.BiMap就是来解决这个问题的.BiMap有一个神奇的方法BiMap<V, K> inverse().可以把Map里面的key,value反过来.BiMap里面key和value都是唯一的不能重复.

对应的BiMap实现 键–值实现 值–键实现
HashBiMap HashMap HashMap
ImmutableBiMap ImmutableMap ImmutableMap
EnumBiMap EnumMap EnumMap
EnumHashBiMap EnumMap HashMap

关于BiMap里面各个类api方法,我们就不展示出来.都是很容易懂的.源码点击去,啥都晓得了.源码才是最讲道理的地方.

2.5 Table

       当我们需要多个索引的数据结构的时候,通常情况下,我们只能用这种丑陋的Map<FirstName,Map<LastName,Person>>来实现。为此Guava提供了一个新的集合类型-Table集合类型,来支持这种数据结构的使用场景。Table支持“row”和“column”,Table是Guava提供的一个接口 Interface Table<R,C,V>,由rowKey+columnKey+value组成它有两个键,一个值,和一个n行三列的数据表类似,n行取决于Table对对象中存储了多少个数据.

对于Table而言里面的每个value都有两个key(rowKey,columnKey)

       Table主要方法介绍,每个方法其实都很好理解:


public interface Table<R, C, V> {


    /**
     * 指定行,列对应的值是否存在
     */
    boolean contains(
            @Nullable @CompatibleWith("R") Object rowKey,
            @Nullable @CompatibleWith("C") Object columnKey);

    /**
     * 指定行对应的值是否存在
     */
    boolean containsRow(@Nullable @CompatibleWith("R") Object rowKey);

    /**
     * 指定列对应的值是否存在
     */
    boolean containsColumn(@Nullable @CompatibleWith("C") Object columnKey);

    /**
     * 值是否存在
     */
    boolean containsValue(@Nullable @CompatibleWith("V") Object value);

    /**
     * 获取指定行,列对应的值
     */
    V get(
            @Nullable @CompatibleWith("R") Object rowKey,
            @Nullable @CompatibleWith("C") Object columnKey);

    /** Returns {@code true} if the table contains no mappings. */
    boolean isEmpty();

    /** 获取元素个数 */
    int size();
    

    // Mutators

    /** 清空 */
    void clear();

    /**
     * 放入元素
     */
    @CanIgnoreReturnValue
    @Nullable
    V put(R rowKey, C columnKey, V value);

    /**
     * 放入元素
     */
    void putAll(Table<? extends R, ? extends C, ? extends V> table);

    /**
     * 移除元素
     */
    @CanIgnoreReturnValue
    @Nullable
    V remove(
            @Nullable @CompatibleWith("R") Object rowKey,
            @Nullable @CompatibleWith("C") Object columnKey);
    

    /**
     * 指定行的所有数据
     */
    Map<C, V> row(R rowKey);

    /**
     * 指定列的所有数据
     */
    Map<R, V> column(C columnKey);

    /**
     * 用元素类型为Table.Cell<R, C, V>的Set表现Table<R, C, V>。
     * Cell类似于Map.Entry,但它是用行和列两个键区分的。
     */
    Set<Table.Cell<R, C, V>> cellSet();

    /**
     * 获取Table里面所有行的key
     */
    Set<R> rowKeySet();

    /**
     * 获取Table里面所有列的key
     */
    Set<C> columnKeySet();

    /**
     * 获取Table里面所有的值
     */
    Collection<V> values();

    /**
     * 用Map<R, Map<C, V>>表现Table<R, C, V>
     */
    Map<R, Map<C, V>> rowMap();

    /**
     * 用Map<C, Map<R, V>>表现Table<R, C, V>
     */
    Map<C, Map<R, V>> columnMap();
}

       Table的实现类,以及内部是用啥数据类型实现的.

对应的Table实现 内部实现
HashBasedTable HashMap<R, HashMap<C, V>>
TreeBasedTable TreeMap<R, TreeMap<C,V>>
ImmutableTable ImmutableMap<R, ImmutableMap<C, V>>
ArrayTable 二维数组

2.6 ClassToInstanceMap

       ClassToInstanceMap提供了一种是用Class作为Key, 对应实例作为Value的途径.他定义了T getInstance(Class)和T putInstance(Class T)两个方法, 这两个方法消除了元素类型转换的过程并保证了元素在Map中是类型安全的.我们使用ClassToInstanceMap的唯一目的就是消除类型转换过程中可能产生的错误.比如在传递参数的时候我们就可以用上ClassToInstanceMap了.

ClassToInstanceMap实现类 解释
MutableClassToInstanceMap 可变类型的ClassToInstanceMap
ImmutableClassToInstanceMap 不可变更的ClassToInstanceMap,我们在对这个Map构造完成后就不可再变更

        ClassToInstanceMap classToInstanceMap = MutableClassToInstanceMap.create();
        classToInstanceMap.putInstance(Integer.class, 10);
        classToInstanceMap.putInstance(Float.class, 10L);
        classToInstanceMap.putInstance(String.class, "abc");

2.7 RangeSet

       RangeSet描述了一组不相连的、非空的区间。当把一个区间添加到可变的RangeSet时,所有相连的区间会被合并,空区间会被忽略。

       关于RangeSet咱们的关注点在两个方面:一个是RangeSet的值是可以比较的所以RangeSet里面的值对应的对象需要实现Comparable接口、第二个是范围,guava里面通过Range类来表示范围。关于Range里面方法我们也做一个简单的介绍(不同的函数代表不同的区间),如下:

概念 表示范围 guava Range类对应方法
(a…b) {x a < x < b}
[a…b] {x a <= x <= b}
[a…b) {x a <= x < b}
(a…b] {x a < x <= b}
(a…+∞) {x x > a}
[a…+∞) {x x >= a}
(-∞…b) {x x < b}
(-∞…b] {x x <= b}
(-∞…+∞) all values all()

       RangeSet方法介绍,如下:

public interface RangeSet<C extends Comparable> {

    /** 是否包含值 */
    boolean contains(C value);

    /**
     * 获取值所在的区间
     */
    Range<C> rangeContaining(C value);

    /**
     * 判断RangeSet中是否有任何区间和给定区间交叉
     */
    boolean intersects(Range<C> otherRange);

    /**
     * 判断RangeSet中是否有任何区间包括给定区间
     */
    boolean encloses(Range<C> otherRange);

    /**
     * 同上,如果RangeSet的范围都在当前RangeSet里面则返回true
     */
    boolean enclosesAll(RangeSet<C> other);

    /**
     * 同上,给定的参数的范围都在当前RangeSet里面则返回true
     */
    default boolean enclosesAll(Iterable<Range<C>> other) {
        for (Range<C> range : other) {
            if (!encloses(range)) {
                return false;
            }
        }
        return true;
    }

    /** 是否为null */
    boolean isEmpty();

    /**
     * 返回包括RangeSet中所有区间的最小区间
     */
    Range<C> span();


    /**
     * 用Set<Range<C>>表现RangeSet,这样可以遍历其中的Range
     */
    Set<Range<C>> asRanges();

    /**
     * 返回组成此范围集的断开连接的范围的降序视图
     */
    Set<Range<C>> asDescendingSetOfRanges();

    /**
     * 返回RangeSet的补集视图。complement也是RangeSet类型,包含了不相连的、非空的区间。
     */
    RangeSet<C> complement();

    /**
     * 返回RangeSet与给定Range的交集视图。这扩展了传统排序集合中的headSet、subSet和tailSet操作
     */
    RangeSet<C> subRangeSet(Range<C> view);


    /**
     * 增加一个范围区间
     */
    void add(Range<C> range);

    /**
     * 移除一个范围区间,如果有交叉的话,会被分割
     */
    void remove(Range<C> range);

    /**
     * 清空
     */
    void clear();

    /**
     * 增加参数里面所有的区间到当前RangeSet里面去
     */
    void addAll(RangeSet<C> other);

    /**
     * 同上把参数给定的区间都增加到当前RangeSet里面去
     */
    default void addAll(Iterable<Range<C>> ranges) {
        for (Range<C> range : ranges) {
            add(range);
        }
    }

    /**
     * 移除参数给定的所有区间,如果有交集的情况会拆分
     */
    void removeAll(RangeSet<C> other);

    /**
     * 移除参数给定的所有区间,如果有交集的情况会拆分
     */
    default void removeAll(Iterable<Range<C>> ranges) {
        for (Range<C> range : ranges) {
            remove(range);
        }
    }


}

       RangeSet实现类,guava提供了两个实现类,有兴趣的也可以进去看看源码,如下:

RangeSet实现类 解释
ImmutableRangeSet 是一个不可修改的RangeSet
TreeRangeSet 利用树的形式来实现

       RangeSet简单使用

		RangeSet rangeSet = TreeRangeSet.create();
		rangeSet.add(Range.closed(1, 10));
		System.out.println(rangeSet);   // [[1..10]]

		rangeSet.add(Range.closedOpen(11, 15));
		System.out.println(rangeSet);   // [[1..10], [11..15)]

		rangeSet.add(Range.open(15, 20));
		System.out.println(rangeSet);   // [[1..10], [11..15), (15..20)]

		rangeSet.add(Range.openClosed(0, 0));
		System.out.println(rangeSet);   // [[1..10], [11..15), (15..20)]

		rangeSet.remove(Range.open(5, 10));
		System.out.println(rangeSet);   // [[1..5], [10..10], [11..15), (15..20)]

2.8 RangeMap

       angeMap描述了”不相交的、非空的区间”到特定值的映射。和RangeSet不同,RangeMap不会合并相邻的映射,即便相邻的区间映射到相同的值。说的简单直白一点RangeMap就是以区间作为键。

       RangeMap方法介绍,如下:

public interface RangeMap<K extends Comparable, V> {
    /**
     * 获取范围对应的元素(子范围也是可以的)
     */
    @Nullable
    V get(K key);

    /**
     * 如果范围映射中存在此类范围,则返回包含此键及其关联值的范围
     * 1. 先根据范围找到值
     * 2. 在根据值找到,所有范围
     */
    @Nullable
    Map.Entry<Range<K>, V> getEntry(K key);

    /**
     * 返回包含此RangeMap中范围的最小范围
     */
    Range<K> span();

    /**
     * 放入一个元素
     */
    void put(Range<K> range, V value);

    /**
     * 将范围映射到指定值,将此范围与具有与此范围相连的相同值的任何现有范围合并
     */
    void putCoalescing(Range<K> range, V value);

    /** 放入值 */
    void putAll(RangeMap<K, V> rangeMap);

    /** 清空 */
    void clear();

    /**
     * 移除
     */
    void remove(Range<K> range);

    /**
     * 将此范围映射的视图作为不可修改的Map<range,V>返回
     */
    Map<Range<K>, V> asMapOfRanges();

    /**
     * 将此范围映射的视图作为不可修改的Map<range,V>返回
     */
    Map<Range<K>, V> asDescendingMapOfRanges();

    /**
     * 返回此范围映射的与范围相交的部分的视图
     */
    RangeMap<K, V> subRangeMap(Range<K> range);
}

       RangeMap有两个实现类。有兴趣的大家可以看看源码。

RangeMap实现类 解释
ImmutableRangeMap 不可以修改的RangeMap
TreeRangeMap 利用树的形式来实现

       RangeMap简单使用:

		RangeMap<Integer, String> rangeMap = TreeRangeMap.create();
		rangeMap.put(Range.closed(1, 10), "foo"); //{[1,10] => "foo"}
		rangeMap.put(Range.open(3, 6), "bar"); //{[1,3] => "foo", (3,6) => "bar", [6,10] => "foo"}
		rangeMap.put(Range.open(10, 20), "foo"); //{[1,3] => "foo", (3,6) => "bar", [6,10] => "foo", (10,20) => "foo"}
		rangeMap.remove(Range.closed(5, 11)); //{[1,3] => "foo", (3,5) => "bar", (11,20) => "foo"}

三 强大的集合工具类

       提供java.util.Collections中没有的集合工具。任何对JDK集合框架有经验的程序员都熟悉和喜欢java.util.Collections包含的工具方法。Guava沿着这些路线提供了更多的工具方法:适用于所有集合的静态方法。这是Guava最流行和成熟的部分之一。

集合接口 属于JDK还是Guava 对应的Guava工具类
Iterable JDK Iterables
Collection JDK Collections2:不要和java.util.Collections混淆
List JDK Lists
Set JDK Sets
SortedSet JDK Sets
Map JDK Maps
SortedMap JDK Maps
Queue JDK Queues
Multiset Guava Multisets
Multimap Guava Multimaps
BiMap Guava Maps
Table Guava Tables

3.1 Iterables

public final class Iterators {

    /**
     * 返回不可修改的迭代器
     */
    public static <T> Iterable<T> unmodifiableIterable(final Iterable<? extends T> iterable);
    @Deprecated
    public static <E> Iterable<E> unmodifiableIterable(ImmutableCollection<E> iterable);


    /** 元素个数 */
    public static int size(Iterable<?> iterable);

    /**
     * 是否包含指定元素
     */
    public static boolean contains(Iterable<?> iterable, @Nullable Object element);

    /**
     * 移除集合类的元素
     */
    @CanIgnoreReturnValue
    public static boolean removeAll(Iterable<?> removeFrom, Collection<?> elementsToRemove);

    /**
     * 交集,完全属于
     */
    @CanIgnoreReturnValue
    public static boolean retainAll(Iterable<?> removeFrom, Collection<?> elementsToRetain);

    /**
     * 移除满足条件的元素
     */
    @CanIgnoreReturnValue
    public static <T> boolean removeIf(Iterable<T> removeFrom, Predicate<? super T> predicate);

    /** 移除第一个满足添加的元素,并且返回该元素 */
    static <T> @Nullable T removeFirstMatching(
            Iterable<T> removeFrom, Predicate<? super T> predicate);

    /**
     * 如果两个iterable中的所有元素相等且顺序一致,返回true
     */
    public static boolean elementsEqual(Iterable<?> iterable1, Iterable<?> iterable2);

    /**
     * 获取iterable中唯一的元素,如果iterable为空或有多个元素,则快速失败
     */
    public static <T> T getOnlyElement(Iterable<T> iterable);
    public static <T> @Nullable T getOnlyElement(
            Iterable<? extends T> iterable, @Nullable T defaultValue);

    /**
     * 返回迭代器里面满足指定类型的元素对应的数据
     */
    @GwtIncompatible // Array.newInstance(Class, int)
    public static <T> T[] toArray(Iterable<? extends T> iterable, Class<T> type);

    /**
     * 把迭代器里面的元素放入到数组里面去
     */
    static <T> T[] toArray(Iterable<? extends T> iterable, T[] array);

    /**
     * 把迭代器里面的元素放入到数组里面去
     */
    static Object[] toArray(Iterable<?> iterable);

    /**
     * 把迭代器里面的元素放入到集合里面去
     */
    private static <E> Collection<E> castOrCopyToCollection(Iterable<E> iterable);

    /**
     * 集合里面的元素都添加到迭代器里面去
     */
    @CanIgnoreReturnValue
    public static <T> boolean addAll(Collection<T> addTo, Iterable<? extends T> elementsToAdd);

    /**
     * 返回对象在iterable中出现的次数
     */
    public static int frequency(Iterable<?> iterable, @Nullable Object element) {
        if ((iterable instanceof Multiset)) {
            return ((Multiset<?>) iterable).count(element);
        } else if ((iterable instanceof Set)) {
            return ((Set<?>) iterable).contains(element) ? 1 : 0;
        }
        return Iterators.frequency(iterable.iterator(), element);
    }

    /**
     * 返回一个循环迭代器,可以比作是双向链表,最后一个又和第一个连接起来
     */
    public static <T> Iterable<T> cycle(final Iterable<T> iterable);
    @SafeVarargs
    public static <T> Iterable<T> cycle(T... elements);

    /**
     * 串联起来
     */
    public static <T> Iterable<T> concat(Iterable<? extends T> a, Iterable<? extends T> b);
    public static <T> Iterable<T> concat(
            Iterable<? extends T> a, Iterable<? extends T> b, Iterable<? extends T> c)
    public static <T> Iterable<T> concat(
            Iterable<? extends T> a,
            Iterable<? extends T> b,
            Iterable<? extends T> c,
            Iterable<? extends T> d);
    @SafeVarargs
    public static <T> Iterable<T> concat(Iterable<? extends T>... inputs);
    public static <T> Iterable<T> concat(Iterable<? extends Iterable<? extends T>> inputs);

    /**
     * 对迭代器做划分,多少个元素一组, 每个分组没满个数的会填null
     * [a, b, c, d, e]} with a partition size of 3 yields {[[a, b, c], [d, e, null]]}
     */
    public static <T> Iterable<List<T>> partition(final Iterable<T> iterable, final int size);

    /**
     * 对迭代器做划分,多少个元素一组, 每个分组没满个数的会填null
     * [a, b, c, d, e]} with a partition size of 3 yields {[[a, b, c], [d, e]]}
     */
    public static <T> Iterable<List<T>> paddedPartition(final Iterable<T> iterable, final int size);

    /**
     * 过滤出满足条件的值
     */
    public static <T> Iterable<T> filter(
            final Iterable<T> unfiltered, final Predicate<? super T> retainIfTrue);

    /**
     * 过滤出指定类型的元素
     */
    @SuppressWarnings("unchecked")
    @GwtIncompatible // Class.isInstance
    public static <T> Iterable<T> filter(final Iterable<?> unfiltered, final Class<T> desiredType);

    /**
     * 迭代器里面只要有一个元素满足条件就返回true
     */
    public static <T> boolean any(Iterable<T> iterable, Predicate<? super T> predicate);

    /**
     * 迭代器里面的每个元素是否都满足条件
     */
    public static <T> boolean all(Iterable<T> iterable, Predicate<? super T> predicate);

    /**
     * 获取满足条件的值
     */
    public static <T> T find(Iterable<T> iterable, Predicate<? super T> predicate);

    /**
     * 获取满足条件的值,如果没有找到返回defaultValue
     */
    public static <T> @Nullable T find(
            Iterable<? extends T> iterable, Predicate<? super T> predicate, @Nullable T defaultValue);

    /**
     * 获取满足条件的值,值用Optional报装
     */
    public static <T> Optional<T> tryFind(Iterable<T> iterable, Predicate<? super T> predicate);

    /**
     * 获取满足条件记录的位置
     */
    public static <T> int indexOf(Iterable<T> iterable, Predicate<? super T> predicate);

    /**
     * 对迭代器里面的每个记录做相应的转换
     */
    public static <F, T> Iterable<T> transform(
            final Iterable<F> fromIterable, final Function<? super F, ? extends T> function);

    /**
     * 获取指定位置记录
     */
    public static <T> T get(Iterable<T> iterable, int position);

    /**
     * 获取指定位置的的记录,如果没有找到返回defaultValue
     */
    public static <T> @Nullable T get(
            Iterable<? extends T> iterable, int position, @Nullable T defaultValue);

    /**
     * 获取第一个记录,如果没有找到就用defaultValue代替
     */
    public static <T> @Nullable T getFirst(Iterable<? extends T> iterable, @Nullable T defaultValue);

    /**
     * 获取最后一个记录
     */
    public static <T> T getLast(Iterable<T> iterable);

    /**
     * 获取最后一个记录,如果没有获取到就是defaultValue
     */
    public static <T> @Nullable T getLast(Iterable<? extends T> iterable, @Nullable T defaultValue);

    /**
     * 获取最后一个记录
     */
    private static <T> T getLastInNonemptyList(List<T> list);

    /**
     * 返回跳过指定元素的Iterable
     */
    public static <T> Iterable<T> skip(final Iterable<T> iterable, final int numberToSkip);

    /**
     * 返回一个(可能)被截取的iterable,元素个数最多为给定值
     */
    public static <T> Iterable<T> limit(final Iterable<T> iterable, final int limitSize);

    /**
     * 返回一个用于过滤、转换集合中的数据
     */
    public static <T> Iterable<T> consumingIterable(final Iterable<T> iterable);

    // Methods only in Iterables, not in Iterators

    /**
     * 判断可迭代对象元素是否为null
     */
    public static boolean isEmpty(Iterable<?> iterable);

    /**
     * 获取排序之后的可迭代对象
     */
    @Beta
    public static <T> Iterable<T> mergeSorted(
            final Iterable<? extends Iterable<? extends T>> iterables,
            final Comparator<? super T> comparator);

}

3.2 Collections2

public final class Collections2 {

    /**
     * 过滤
     */
    public static <E> Collection<E> filter(Collection<E> unfiltered, Predicate<? super E> predicate);

    /**
     * 转换
     */
    public static <F, T> Collection<T> transform(
            Collection<F> fromCollection, Function<? super F, T> function);

    /**
     * 先将元素排序,在排列
     */
    @Beta
    public static <E extends Comparable<? super E>> Collection<List<E>> orderedPermutations(
            Iterable<E> elements);
    @Beta
    public static <E> Collection<List<E>> orderedPermutations(
            Iterable<E> elements, Comparator<? super E> comparator);

    /**
     * 直接排列
     */
    @Beta
    public static <E> Collection<List<E>> permutations(Collection<E> elements);

}

3.3 Lists

public final class Lists {

    /**
     * 构造ArrayList
     */
    @GwtCompatible(serializable = true)
    public static <E> ArrayList<E> newArrayList();
    @SafeVarargs
    @GwtCompatible(serializable = true)
    public static <E> ArrayList<E> newArrayList(E... elements);
    @GwtCompatible(serializable = true)
    public static <E> ArrayList<E> newArrayList(Iterable<? extends E> elements);
    @GwtCompatible(serializable = true)
    public static <E> ArrayList<E> newArrayList(Iterator<? extends E> elements);
    

    /**
     * 构造一个带初始化带大小initialArraySize的ArrayList实例
     */
    @GwtCompatible(serializable = true)
    public static <E> ArrayList<E> newArrayListWithCapacity(int initialArraySize);

    /**
     * 构造一个期望长度为estimatedSize的ArrayList实例
     */
    @GwtCompatible(serializable = true)
    public static <E> ArrayList<E> newArrayListWithExpectedSize(int estimatedSize);

    // LinkedList

    /**
     * 获取LinkedList
     */
    @GwtCompatible(serializable = true)
    public static <E> LinkedList<E> newLinkedList();
    @GwtCompatible(serializable = true)
    public static <E> LinkedList<E> newLinkedList(Iterable<? extends E> elements);

    /**
     * CopyOnWriteArrayList 读写分离,线程安志的List
     */
    @GwtIncompatible // CopyOnWriteArrayList
    public static <E> CopyOnWriteArrayList<E> newCopyOnWriteArrayList();
    @GwtIncompatible // CopyOnWriteArrayList
    public static <E> CopyOnWriteArrayList<E> newCopyOnWriteArrayList(
            Iterable<? extends E> elements);

    /**
     * 转坏为List
     */
    public static <E> List<E> asList(@Nullable E first, E[] rest);
    public static <E> List<E> asList(@Nullable E first, @Nullable E second, E[] rest);


    /**
     * 对集合做笛卡尔操作
     * 假设集合A={a,b},集合B={0,1,2},则两个集合的笛卡尔积为{(a,0),(a,1),(a,2),(b,0),(b,1),(b,2)}
     */
    public static <B> List<List<B>> cartesianProduct(List<? extends List<? extends B>> lists);
    @SafeVarargs
    public static <B> List<List<B>> cartesianProduct(List<? extends B>... lists);

    /**
     * 对list里面的每个元素做转换
     */
    public static <F, T> List<T> transform(
            List<F> fromList, Function<? super F, ? extends T> function);



    /**
     * 对list做分区处理
     */
    public static <T> List<List<T>> partition(List<T> list, int size);


    /**
     * String转换成不可变更的ImmutableList<Character>
     */
    public static ImmutableList<Character> charactersOf(String string);

    /**
     * CharSequence转list
     */
    @Beta
    public static List<Character> charactersOf(CharSequence sequence);

    /**
     * 反转
     */
    public static <T> List<T> reverse(List<T> list);


}

3.4 Sets

public final class Sets {

    /**
     * 返回一个包含给定枚举元素的不可变的Set实例
     */
    // http://code.google.com/p/google-web-toolkit/issues/detail?id=3028
    @GwtCompatible(serializable = true)
    public static <E extends Enum<E>> ImmutableSet<E> immutableEnumSet(
            E anElement, E... otherElements);
    @GwtCompatible(serializable = true)
    public static <E extends Enum<E>> ImmutableSet<E> immutableEnumSet(Iterable<E> elements);


    /**
     * 返回一个Collector
     */
    public static <E extends Enum<E>> Collector<E, ?, ImmutableSet<E>> toImmutableEnumSet();

    /**
     * 返回一个EnumSet实例
     */
    public static <E extends Enum<E>> EnumSet<E> newEnumSet();

    // HashSet

    /**
     * 返回一个可变的HashSet实例
     */
    public static <E> HashSet<E> newHashSet();
    public static <E> HashSet<E> newHashSet(E... elements);
    public static <E> HashSet<E> newHashSet(Iterable<? extends E> elements);
    public static <E> HashSet<E> newHashSet(Iterator<? extends E> elements);

    /**
     * 构造一个期望长度为expectedSize的HashSet实例
     */
    public static <E> HashSet<E> newHashSetWithExpectedSize(int expectedSize);

    /**
     * 创建一个线程安全的Set,由ConcurrentHashMap的实例支持,因此进行了相同的并发性担保,
     * 与HashSet不同的是,这个Set不允许null元素,该Set是可序列化的。
     */
    public static <E> Set<E> newConcurrentHashSet();

    /**
     * 创建一个线程安全的Set,包含给定的元素,由ConcurrentHashMap的实例支持,因此进行了相同的并发性担保,
     * 与 HashSet不同的是,这个Set不允许null元素,该Set是可序列化的
     */
    public static <E> Set<E> newConcurrentHashSet(Iterable<? extends E> elements);

    // LinkedHashSet

    /**
     * 创建一个可变的、空的LinkedHashSet实例
     */
    public static <E> LinkedHashSet<E> newLinkedHashSet();

    /**
     * 构造一个包含给定元素的LinkedHashSet实例
     */
    public static <E> LinkedHashSet<E> newLinkedHashSet(Iterable<? extends E> elements);

    /**
     * 构造一个期望长度为expectedSize的LinkedHashSet实例
     */
    public static <E> LinkedHashSet<E> newLinkedHashSetWithExpectedSize(int expectedSize);

    // TreeSet

    /**
     * 返回一个可变的空的TreeSet实例
     */
    public static <E extends Comparable> TreeSet<E> newTreeSet();

    /**
     * 返回一个可变的包含给定元素的TreeSet实例
     */
    public static <E extends Comparable> TreeSet<E> newTreeSet(Iterable<? extends E> elements);

    /**
     * 创建一个具有给定的比较器可变TreeSet的实例
     */
    public static <E> TreeSet<E> newTreeSet(Comparator<? super E> comparator);

    /**
     * 创建一个空的Set
     */
    public static <E> Set<E> newIdentityHashSet() {
        return Collections.newSetFromMap(Maps.<E, Boolean>newIdentityHashMap());
    }

    /**
     * 生成一个CopyOnWriteArraySet,CopyOnWriteArraySet读写分离,线程安全
     */
    @GwtIncompatible // CopyOnWriteArraySet
    public static <E> CopyOnWriteArraySet<E> newCopyOnWriteArraySet();
    @GwtIncompatible // CopyOnWriteArraySet
    public static <E> CopyOnWriteArraySet<E> newCopyOnWriteArraySet(Iterable<? extends E> elements);

    /**
     * 创建一个枚举EnumSet
     */
    public static <E extends Enum<E>> EnumSet<E> complementOf(Collection<E> collection);

    /**
     * 创建一个枚举EnumSet,并且里面是值是除了type类型之外的值
     */
    public static <E extends Enum<E>> EnumSet<E> complementOf(
            Collection<E> collection, Class<E> type);


    /**
     * 基于指定的Map对象创建一个新的Set对象
     */
    @Deprecated
    public static <E> Set<E> newSetFromMap(Map<E, Boolean> map);


    /**
     * 合集,并集
     */
    public static <E> com.google.common.collect.Sets.SetView<E> union(final Set<? extends E> set1, final Set<? extends E> set2);

    /**
     * 交集
     */
    public static <E> com.google.common.collect.Sets.SetView<E> intersection(final Set<E> set1, final Set<?> set2);

    /**
     * 差集
     */
    public static <E> com.google.common.collect.Sets.SetView<E> difference(final Set<E> set1, final Set<?> set2);

    /**
     * 对等差分
     * 给出两个集合 (如集合 A = {1, 2, 3} 和集合 B = {2, 3, 4}),
     * 而数学术语 "对等差分" 的集合就是指由所有只在两个集合其中之一的元素组成的集合(A △ B = C = {1, 4})
     */
    public static <E> com.google.common.collect.Sets.SetView<E> symmetricDifference(
            final Set<? extends E> set1, final Set<? extends E> set2);

    /**
     * 过滤
     */
    // TODO(kevinb): how to omit that last sentence when building GWT javadoc?
    public static <E> Set<E> filter(Set<E> unfiltered, com.google.common.base.Predicate<? super E> predicate);
    public static <E> SortedSet<E> filter(SortedSet<E> unfiltered, com.google.common.base.Predicate<? super E> predicate);
    @GwtIncompatible // NavigableSet
    @SuppressWarnings("unchecked")
    public static <E> NavigableSet<E> filter(
            NavigableSet<E> unfiltered, com.google.common.base.Predicate<? super E> predicate);

    /**
     * 对Set做笛卡尔操作
     *
     * 假设集合A={a,b},集合B={0,1,2},则两个集合的笛卡尔积为{(a,0),(a,1),(a,2),(b,0),(b,1),(b,2)}
     */
    public static <B> Set<List<B>> cartesianProduct(List<? extends Set<? extends B>> sets);
    @SafeVarargs
    public static <B> Set<List<B>> cartesianProduct(Set<? extends B>... sets) {
        return cartesianProduct(Arrays.asList(sets));
    }


    /**
     *
     * 返回Set的所有可能子集的集合。
     * 例如 powerSet(ImmutableSet.of(1, 2))} returns the set {@code {{}, {1}, {2}, {1, 2}}}.
     */
    @GwtCompatible(serializable = false)
    public static <E> Set<Set<E>> powerSet(Set<E> set) {
        return new com.google.common.collect.Sets.PowerSet<E>(set);
    }


    /**
     * 返回大小为size的Set的所有子集的集合
     * 例如 combinations(ImmutableSet.of(1, 2, 3), 2)} returns the set {@code {{1, 2}, {1, 3}, {2, 3}}}.
     */
    @Beta
    public static <E> Set<Set<E>> combinations(Set<E> set, final int size);


    /**
     * 返回一个不可修改的NavigableSet
     */
    public static <E> NavigableSet<E> unmodifiableNavigableSet(NavigableSet<E> set);

    /**
     * 返回一个同步的(线程安全的)NavigableSet
     */
    @GwtIncompatible // NavigableSet
    public static <E> NavigableSet<E> synchronizedNavigableSet(NavigableSet<E> navigableSet) {
        return Synchronized.navigableSet(navigableSet);
    }


    /**
     * 获取范围内的Set
     */
    @Beta
    @GwtIncompatible // NavigableSet
    public static <K extends Comparable<? super K>> NavigableSet<K> subSet(
            NavigableSet<K> set, Range<K> range);
}

3.5 Maps

public final class Maps {

    /**
     * 创建ImmutableMap -- 不可以修改的Map
     */
    @GwtCompatible(serializable = true)
    public static <K extends Enum<K>, V> ImmutableMap<K, V> immutableEnumMap(
            Map<K, ? extends V> map);

    /**
     * 创建Collector
     */
    public static <T, K extends Enum<K>, V> Collector<T, ?, ImmutableMap<K, V>> toImmutableEnumMap(
            java.util.function.Function<? super T, ? extends K> keyFunction,
            java.util.function.Function<? super T, ? extends V> valueFunction);
    public static <T, K extends Enum<K>, V> Collector<T, ?, ImmutableMap<K, V>> toImmutableEnumMap(
            java.util.function.Function<? super T, ? extends K> keyFunction,
            java.util.function.Function<? super T, ? extends V> valueFunction,
            BinaryOperator<V> mergeFunction);

    /**
     * 创建HashMap
     */
    public static <K, V> HashMap<K, V> newHashMap();
    public static <K, V> HashMap<K, V> newHashMap(Map<? extends K, ? extends V> map);

    /**
     * 创建LinkedHashMap
     */
    public static <K, V> LinkedHashMap<K, V> newLinkedHashMap();
    public static <K, V> LinkedHashMap<K, V> newLinkedHashMap(Map<? extends K, ? extends V> map);

    /**
     * 构造一个期望长度为estimatedSize的LinkedHashMap实例
     */
    public static <K, V> LinkedHashMap<K, V> newLinkedHashMapWithExpectedSize(int expectedSize);

    /**
     * ConcurrentMap -- 是一个能够支持并发访问的java.util.map集合
     */
    public static <K, V> ConcurrentMap<K, V> newConcurrentMap();

    /**
     * TreeMap
     */
    public static <K extends Comparable, V> TreeMap<K, V> newTreeMap();
    public static <K, V> TreeMap<K, V> newTreeMap(SortedMap<K, ? extends V> map);
    public static <C, K extends C, V> TreeMap<K, V> newTreeMap(@Nullable Comparator<C> comparator);

    /**
     * 创建一个EnumMap
     */
    public static <K extends Enum<K>, V> EnumMap<K, V> newEnumMap(Class<K> type);
    public static <K extends Enum<K>, V> EnumMap<K, V> newEnumMap(Map<K, ? extends V> map);

    /**
     * 创建一个空的Map
     */
    public static <K, V> IdentityHashMap<K, V> newIdentityHashMap() {
        return new IdentityHashMap<>();
    }

    /**
     * 差集
     */
    @SuppressWarnings("unchecked")
    public static <K, V> MapDifference<K, V> difference(
            Map<? extends K, ? extends V> left, Map<? extends K, ? extends V> right);
    public static <K, V> MapDifference<K, V> difference(
            Map<? extends K, ? extends V> left,
            Map<? extends K, ? extends V> right,
            Equivalence<? super V> valueEquivalence);
    public static <K, V> SortedMapDifference<K, V> difference(
            SortedMap<K, ? extends V> left, Map<? extends K, ? extends V> right);

    /**
     * 转换为Map
     */
    public static <K, V> Map<K, V> asMap(Set<K> set, Function<? super K, V> function);
    /**
     * 转换为SortedMap
     */
    public static <K, V> SortedMap<K, V> asMap(SortedSet<K> set, Function<? super K, V> function);
    /**
     * 转换为NavigableMap
     */
    @GwtIncompatible // NavigableMap
    public static <K, V> NavigableMap<K, V> asMap(
            NavigableSet<K> set, Function<? super K, V> function);


    /**
     * value做相应的转换之后,生成ImmutableMap
     */
    public static <K, V> ImmutableMap<K, V> toMap(
            Iterable<K> keys, Function<? super K, V> valueFunction);
    public static <K, V> ImmutableMap<K, V> toMap(
            Iterator<K> keys, Function<? super K, V> valueFunction);

    /**
     * key做相应的转换之后,生成ImmutableMap
     */
    @CanIgnoreReturnValue
    public static <K, V> ImmutableMap<K, V> uniqueIndex(
            Iterable<V> values, Function<? super V, K> keyFunction);
    @CanIgnoreReturnValue
    public static <K, V> ImmutableMap<K, V> uniqueIndex(
            Iterator<V> values, Function<? super V, K> keyFunction);

    /**
     * 属性文件里面读到的内容Properties转换为ImmutableMap
     */
    @GwtIncompatible // java.util.Properties
    public static ImmutableMap<String, String> fromProperties(Properties properties);

    /**
     * 生成不可以修改的Entry
     */
    @GwtCompatible(serializable = true)
    public static <K, V> Entry<K, V> immutableEntry(@Nullable K key, @Nullable V value);


    /**
     * BiMapConverter
     */
    public static <A, B> Converter<A, B> asConverter(final BiMap<A, B> bimap);

    /**
     * 线程安全的BiMap
     */
    public static <K, V> BiMap<K, V> synchronizedBiMap(BiMap<K, V> bimap);

    /**
     * 不可以修改的BiMap
     */
    public static <K, V> BiMap<K, V> unmodifiableBiMap(BiMap<? extends K, ? extends V> bimap);


    /**
     * 转换值
     */
    public static <K, V1, V2> Map<K, V2> transformValues(
            Map<K, V1> fromMap, Function<? super V1, V2> function);
    public static <K, V1, V2> SortedMap<K, V2> transformValues(
            SortedMap<K, V1> fromMap, Function<? super V1, V2> function);
    @GwtIncompatible // NavigableMap
    public static <K, V1, V2> NavigableMap<K, V2> transformValues(
            NavigableMap<K, V1> fromMap, Function<? super V1, V2> function);

    /**
     * 转换
     */
    public static <K, V1, V2> Map<K, V2> transformEntries(
            Map<K, V1> fromMap, EntryTransformer<? super K, ? super V1, V2> transformer);
    public static <K, V1, V2> SortedMap<K, V2> transformEntries(
            SortedMap<K, V1> fromMap, EntryTransformer<? super K, ? super V1, V2> transformer);
    @GwtIncompatible // NavigableMap
    public static <K, V1, V2> NavigableMap<K, V2> transformEntries(
            final NavigableMap<K, V1> fromMap, EntryTransformer<? super K, ? super V1, V2> transformer);


    @GwtIncompatible // NavigableMap
    private static class TransformedEntriesNavigableMap<K, V1, V2>
            extends TransformedEntriesSortedMap<K, V1, V2> implements NavigableMap<K, V2> {

        TransformedEntriesNavigableMap(
                NavigableMap<K, V1> fromMap, EntryTransformer<? super K, ? super V1, V2> transformer) {
            super(fromMap, transformer);
        }

        @Override
        public Entry<K, V2> ceilingEntry(K key) {
            return transformEntry(fromMap().ceilingEntry(key));
        }

        @Override
        public K ceilingKey(K key) {
            return fromMap().ceilingKey(key);
        }

        @Override
        public NavigableSet<K> descendingKeySet() {
            return fromMap().descendingKeySet();
        }

        @Override
        public NavigableMap<K, V2> descendingMap() {
            return transformEntries(fromMap().descendingMap(), transformer);
        }

        @Override
        public Entry<K, V2> firstEntry() {
            return transformEntry(fromMap().firstEntry());
        }

        @Override
        public Entry<K, V2> floorEntry(K key) {
            return transformEntry(fromMap().floorEntry(key));
        }

        @Override
        public K floorKey(K key) {
            return fromMap().floorKey(key);
        }

        @Override
        public NavigableMap<K, V2> headMap(K toKey) {
            return headMap(toKey, false);
        }

        @Override
        public NavigableMap<K, V2> headMap(K toKey, boolean inclusive) {
            return transformEntries(fromMap().headMap(toKey, inclusive), transformer);
        }

        @Override
        public Entry<K, V2> higherEntry(K key) {
            return transformEntry(fromMap().higherEntry(key));
        }

        @Override
        public K higherKey(K key) {
            return fromMap().higherKey(key);
        }

        @Override
        public Entry<K, V2> lastEntry() {
            return transformEntry(fromMap().lastEntry());
        }

        @Override
        public Entry<K, V2> lowerEntry(K key) {
            return transformEntry(fromMap().lowerEntry(key));
        }

        @Override
        public K lowerKey(K key) {
            return fromMap().lowerKey(key);
        }

        @Override
        public NavigableSet<K> navigableKeySet() {
            return fromMap().navigableKeySet();
        }

        @Override
        public Entry<K, V2> pollFirstEntry() {
            return transformEntry(fromMap().pollFirstEntry());
        }

        @Override
        public Entry<K, V2> pollLastEntry() {
            return transformEntry(fromMap().pollLastEntry());
        }

        @Override
        public NavigableMap<K, V2> subMap(
                K fromKey, boolean fromInclusive, K toKey, boolean toInclusive) {
            return transformEntries(
                    fromMap().subMap(fromKey, fromInclusive, toKey, toInclusive), transformer);
        }

        @Override
        public NavigableMap<K, V2> subMap(K fromKey, K toKey) {
            return subMap(fromKey, true, toKey, false);
        }

        @Override
        public NavigableMap<K, V2> tailMap(K fromKey) {
            return tailMap(fromKey, true);
        }

        @Override
        public NavigableMap<K, V2> tailMap(K fromKey, boolean inclusive) {
            return transformEntries(fromMap().tailMap(fromKey, inclusive), transformer);
        }

        private @Nullable Entry<K, V2> transformEntry(@Nullable Entry<K, V1> entry) {
            return (entry == null) ? null : Maps.transformEntry(transformer, entry);
        }

        @Override
        protected NavigableMap<K, V1> fromMap() {
            return (NavigableMap<K, V1>) super.fromMap();
        }
    }

    static <K> Predicate<Entry<K, ?>> keyPredicateOnEntries(Predicate<? super K> keyPredicate) {
        return compose(keyPredicate, Maps.<K>keyFunction());
    }

    static <V> Predicate<Entry<?, V>> valuePredicateOnEntries(Predicate<? super V> valuePredicate) {
        return compose(valuePredicate, Maps.<V>valueFunction());
    }

    /**
     * 根据key过滤
     */
    public static <K, V> Map<K, V> filterKeys(
            Map<K, V> unfiltered, final Predicate<? super K> keyPredicate);
    public static <K, V> SortedMap<K, V> filterKeys(
            SortedMap<K, V> unfiltered, final Predicate<? super K> keyPredicate);
    @GwtIncompatible // NavigableMap
    public static <K, V> NavigableMap<K, V> filterKeys(
            NavigableMap<K, V> unfiltered, final Predicate<? super K> keyPredicate);
    public static <K, V> BiMap<K, V> filterKeys(
            BiMap<K, V> unfiltered, final Predicate<? super K> keyPredicate);

    /**
     * 根据值过滤
     */
    public static <K, V> Map<K, V> filterValues(
            Map<K, V> unfiltered, final Predicate<? super V> valuePredicate);
    public static <K, V> SortedMap<K, V> filterValues(
            SortedMap<K, V> unfiltered, final Predicate<? super V> valuePredicate);
    @GwtIncompatible // NavigableMap
    public static <K, V> NavigableMap<K, V> filterValues(
            NavigableMap<K, V> unfiltered, final Predicate<? super V> valuePredicate);
    public static <K, V> BiMap<K, V> filterValues(
            BiMap<K, V> unfiltered, final Predicate<? super V> valuePredicate);

    /**
     * 过滤
     */
    public static <K, V> Map<K, V> filterEntries(
            Map<K, V> unfiltered, Predicate<? super Entry<K, V>> entryPredicate);
    public static <K, V> SortedMap<K, V> filterEntries(
            SortedMap<K, V> unfiltered, Predicate<? super Entry<K, V>> entryPredicate);
    @GwtIncompatible // NavigableMap
    public static <K, V> NavigableMap<K, V> filterEntries(
            NavigableMap<K, V> unfiltered, Predicate<? super Entry<K, V>> entryPredicate);
    public static <K, V> BiMap<K, V> filterEntries(
            BiMap<K, V> unfiltered, Predicate<? super Entry<K, V>> entryPredicate);

    /**
     * 返回一个不可修改的NavigableMap
     */
    @GwtIncompatible // NavigableMap
    public static <K, V> NavigableMap<K, V> unmodifiableNavigableMap(
            NavigableMap<K, ? extends V> map);


    /**
     * 返回一个同步的(线程安全的)NavigableMap
     */
    @GwtIncompatible // NavigableMap
    public static <K, V> NavigableMap<K, V> synchronizedNavigableMap(
            NavigableMap<K, V> navigableMap);


    /**
     * key范围内的Map
     */
    @Beta
    @GwtIncompatible // NavigableMap
    public static <K extends Comparable<? super K>, V> NavigableMap<K, V> subMap(
            NavigableMap<K, V> map, Range<K> range);
}

3.6 Queues

public final class Queues {

    /**
     * 创建ArrayBlockingQueue
     */
    @GwtIncompatible // ArrayBlockingQueue
    public static <E> ArrayBlockingQueue<E> newArrayBlockingQueue(int capacity);
    // ArrayDeque

    /**
     * 创建ArrayDeque
     */
    public static <E> ArrayDeque<E> newArrayDeque();

    /**
     * 创建ArrayDeque
     */
    public static <E> ArrayDeque<E> newArrayDeque(Iterable<? extends E> elements);

    // ConcurrentLinkedQueue

    /** 创建ConcurrentLinkedQueue */
    @GwtIncompatible // ConcurrentLinkedQueue
    public static <E> ConcurrentLinkedQueue<E> newConcurrentLinkedQueue();

    /**
     * 创建ConcurrentLinkedQueue
     */
    @GwtIncompatible // ConcurrentLinkedQueue
    public static <E> ConcurrentLinkedQueue<E> newConcurrentLinkedQueue(
            Iterable<? extends E> elements);

    // LinkedBlockingDeque

    /**
     * LinkedBlockingDeque
     */
    @GwtIncompatible // LinkedBlockingDeque
    public static <E> LinkedBlockingDeque<E> newLinkedBlockingDeque();

    /**
     * LinkedBlockingDeque
     */
    @GwtIncompatible // LinkedBlockingDeque
    public static <E> LinkedBlockingDeque<E> newLinkedBlockingDeque(int capacity);

    /**
     * LinkedBlockingDeque
     */
    @GwtIncompatible // LinkedBlockingDeque
    public static <E> LinkedBlockingDeque<E> newLinkedBlockingDeque(Iterable<? extends E> elements);

    // LinkedBlockingQueue

    /** LinkedBlockingQueue */
    @GwtIncompatible // LinkedBlockingQueue
    public static <E> LinkedBlockingQueue<E> newLinkedBlockingQueue();

    /**
     * LinkedBlockingQueue
     */
    @GwtIncompatible // LinkedBlockingQueue
    public static <E> LinkedBlockingQueue<E> newLinkedBlockingQueue(int capacity);

    /**
     * LinkedBlockingQueue
     */
    @GwtIncompatible // LinkedBlockingQueue
    public static <E> LinkedBlockingQueue<E> newLinkedBlockingQueue(Iterable<? extends E> elements);


    /**
     * PriorityBlockingQueue
     */
    @GwtIncompatible // PriorityBlockingQueue
    public static <E extends Comparable> PriorityBlockingQueue<E> newPriorityBlockingQueue();

    /**
     * PriorityBlockingQueue
     */
    @GwtIncompatible // PriorityBlockingQueue
    public static <E extends Comparable> PriorityBlockingQueue<E> newPriorityBlockingQueue(
            Iterable<? extends E> elements);

    // PriorityQueue

    /**
     * PriorityQueue
     */
    public static <E extends Comparable> PriorityQueue<E> newPriorityQueue();

    /**
     * PriorityQueue
     */
    public static <E extends Comparable> PriorityQueue<E> newPriorityQueue(
            Iterable<? extends E> elements);

    // SynchronousQueue

    /** SynchronousQueue 同步Queue,线程安全 */
    @GwtIncompatible // SynchronousQueue
    public static <E> SynchronousQueue<E> newSynchronousQueue();

    /**
     * 一次性的从BlockingQueue获取多少个数据
     */
    @Beta
    @CanIgnoreReturnValue
    @GwtIncompatible // BlockingQueue
    @SuppressWarnings("GoodTime") // should accept a java.time.Duration
    public static <E> int drain(
            BlockingQueue<E> q,
            Collection<? super E> buffer,
            int numElements,
            long timeout,
            TimeUnit unit)
            throws InterruptedException;

    /**
     * 从BlockingQueue里面获取数据,和drain的区别就是当有异常的时候也会停止获取
     */
    @Beta
    @CanIgnoreReturnValue
    @GwtIncompatible // BlockingQueue
    @SuppressWarnings("GoodTime") // should accept a java.time.Duration
    public static <E> int drainUninterruptibly(
            BlockingQueue<E> q,
            Collection<? super E> buffer,
            int numElements,
            long timeout,
            TimeUnit unit);

    /**
     * 获取同步Queue, 同步Queue是线程安全的
     */
    public static <E> Queue<E> synchronizedQueue(Queue<E> queue);

    /**
     * 获取同步的Deque,Deque是双端队列
     */
    public static <E> Deque<E> synchronizedDeque(Deque<E> deque);
}

3.7 Multisets

public final class Multisets {

    /**
     * 用于生成一个Collector,T代表流中的一个一个元素,R代表最终的结果。参考Collector.of()的实现
     */
    public static <T, E, M extends Multiset<E>> Collector<T, ?, M> toMultiset(
            java.util.function.Function<? super T, E> elementFunction,
            java.util.function.ToIntFunction<? super T> countFunction,
            java.util.function.Supplier<M> multisetSupplier);

    /**
     * 转换为不可以修改的Multiset
     */
    public static <E> Multiset<E> unmodifiableMultiset(Multiset<? extends E> multiset);

    /**
     * 转换为不可以修改的Multiset
     */
    @Deprecated
    public static <E> Multiset<E> unmodifiableMultiset(ImmutableMultiset<E> multiset);

    /**
     * 转换为不可以修改的SortedMultiset
     */
    @Beta
    public static <E> SortedMultiset<E> unmodifiableSortedMultiset(SortedMultiset<E> sortedMultiset);

    /**
     * Returns an immutable multiset entry with the specified element and count. The entry will be
     * serializable if {@code e} is.
     *
     * @param e the element to be associated with the returned entry
     * @param n the count to be associated with the returned entry
     * @throws IllegalArgumentException if {@code n} is negative
     */
    public static <E> Multiset.Entry<E> immutableEntry(@Nullable E e, int n) {
        return new com.google.common.collect.Multisets.ImmutableEntry<E>(e, n);
    }

    /**
     * 过滤
     */
    @Beta
    public static <E> Multiset<E> filter(Multiset<E> unfiltered, Predicate<? super E> predicate);

    /**
     * 交集
     */
    public static <E> Multiset<E> intersection(
            final Multiset<E> multiset1, final Multiset<?> multiset2);

    /**
     * 合集
     */
    @Beta
    public static <E> Multiset<E> sum(
            final Multiset<? extends E> multiset1, final Multiset<? extends E> multiset2);

    /**
     * 差集
     */
    @Beta
    public static <E> Multiset<E> difference(
            final Multiset<E> multiset1, final Multiset<?> multiset2);

    /**
     * 对任意o,如果subMultiset.count(o)<=superMultiset.count(o),返回true
     * 和containsAll()是有区别的,containsAll是指包含所有不重复的元素。举两个例子
     *
     * Multiset<String> multiset1 = HashMultiset.create();
     * multiset1.add("a", 2);
     * multiset1.add("b");
     *
     * Multiset<String> multiset2 = HashMultiset.create();
     * multiset2.add("a", 5);
     *
     * multiset1.containsAll(multiset2); // 返回true;因为包含了所有不重复元素,
     *
     * Multisets.containsOccurrences(multiset1, multiset2); // returns false
     */
    @CanIgnoreReturnValue
    public static boolean containsOccurrences(Multiset<?> superMultiset, Multiset<?> subMultiset);

    /**
     * 修改multisetToModify,以保证任意o都符合multisetToModify.count(o)<=multisetToRetain.count(o)
     */
    @CanIgnoreReturnValue
    public static boolean retainOccurrences(
            Multiset<?> multisetToModify, Multiset<?> multisetToRetain);

    /**
     * 对occurrencesToRemove中的重复元素,仅在multisetToModify中删除相同个数。
     * Multiset<String> multiset1 = HashMultiset.create();
     * multiset1.add("a", 2);
     *
     * Multiset<String> multiset2 = HashMultiset.create();
     * multiset2.add("a", 5);
     *
     * multiset2.removeOccurrences(multiset1); // multiset2 现在包含3个"a"
     */
    @CanIgnoreReturnValue
    public static boolean removeOccurrences(
            Multiset<?> multisetToModify, Iterable<?> occurrencesToRemove);
    @CanIgnoreReturnValue
    public static boolean removeOccurrences(
            Multiset<?> multisetToModify, Multiset<?> occurrencesToRemove);

    /**
     * 返回Multiset的不可变拷贝,并将元素按重复出现的次数做降序排列
     */
    @Beta
    public static <E> ImmutableMultiset<E> copyHighestCountFirst(Multiset<E> multiset);
}

3.8 Multimaps

public final class Multimaps {

    /**
     * 用于生成一个Collector,T代表流中的一个一个元素,R代表最终的结果。参考Collector.of()的实现
     */
    @Beta
    public static <T, K, V, M extends Multimap<K, V>> Collector<T, ?, M> toMultimap(
            java.util.function.Function<? super T, ? extends K> keyFunction,
            java.util.function.Function<? super T, ? extends V> valueFunction,
            java.util.function.Supplier<M> multimapSupplier);

    /**
     * 用于生成一个Collector,T代表流中的一个一个元素,R代表最终的结果。参考Collector.of()的实现
     */
    @Beta
    public static <T, K, V, M extends Multimap<K, V>> Collector<T, ?, M> flatteningToMultimap(
            java.util.function.Function<? super T, ? extends K> keyFunction,
            java.util.function.Function<? super T, ? extends Stream<? extends V>> valueFunction,
            java.util.function.Supplier<M> multimapSupplier);

    /**
     * 生成Multimap
     */
    public static <K, V> Multimap<K, V> newMultimap(
            Map<K, Collection<V>> map, final Supplier<? extends Collection<V>> factory);

    /**
     * 生成ListMultimap
     */
    public static <K, V> ListMultimap<K, V> newListMultimap(
            Map<K, Collection<V>> map, final Supplier<? extends List<V>> factory);

    /**
     * 生成SetMultimap
     */
    public static <K, V> SetMultimap<K, V> newSetMultimap(
            Map<K, Collection<V>> map, final Supplier<? extends Set<V>> factory);


    /**
     * 生成SortedSetMultimap
     */
    public static <K, V> SortedSetMultimap<K, V> newSortedSetMultimap(
            Map<K, Collection<V>> map, final Supplier<? extends SortedSet<V>> factory);


    /**
     * 反转Multimap
     */
    @CanIgnoreReturnValue
    public static <K, V, M extends Multimap<K, V>> M invertFrom(
            Multimap<? extends V, ? extends K> source, M dest);

    /**
     * 生成同步Multimap -- 线程安全
     */
    public static <K, V> Multimap<K, V> synchronizedMultimap(Multimap<K, V> multimap);

    /**
     * 生成不可以修改的Multimap
     */
    public static <K, V> Multimap<K, V> unmodifiableMultimap(Multimap<K, V> delegate);
    @Deprecated
    public static <K, V> Multimap<K, V> unmodifiableMultimap(ImmutableMultimap<K, V> delegate);


    /**
     * 生成同步SetMultimap -- 线程安全
     */
    public static <K, V> SetMultimap<K, V> synchronizedSetMultimap(SetMultimap<K, V> multimap);

    /**
     * 生成不可以修改的SetMultimap
     */
    public static <K, V> SetMultimap<K, V> unmodifiableSetMultimap(SetMultimap<K, V> delegate);
    @Deprecated
    public static <K, V> SetMultimap<K, V> unmodifiableSetMultimap(
            ImmutableSetMultimap<K, V> delegate);

    /**
     * 生成同步SortedSetMultimap -- 线程安全
     */
    public static <K, V> SortedSetMultimap<K, V> synchronizedSortedSetMultimap(
            SortedSetMultimap<K, V> multimap);

    /**
     * 生成不可以修改的SortedSetMultimap
     */
    public static <K, V> SortedSetMultimap<K, V> unmodifiableSortedSetMultimap(
            SortedSetMultimap<K, V> delegate);

    /**
     * 生成同步的ListMultimap -- 线程安全
     */
    public static <K, V> ListMultimap<K, V> synchronizedListMultimap(ListMultimap<K, V> multimap);

    /**
     * 生成不可以修改的ListMultimap
     */
    public static <K, V> ListMultimap<K, V> unmodifiableListMultimap(ListMultimap<K, V> delegate);
    @Deprecated
    public static <K, V> ListMultimap<K, V> unmodifiableListMultimap(
            ImmutableListMultimap<K, V> delegate);

    /**
     * 生成不可修改的Collection
     */
    private static <V> Collection<V> unmodifiableValueCollection(Collection<V> collection);

    /**
     * 生成不可修改的Collection
     */
    private static <K, V> Collection<Entry<K, V>> unmodifiableEntries(
            Collection<Entry<K, V>> entries);

    /**
     * ListMultimap转换为Map
     */
    @Beta
    @SuppressWarnings("unchecked")
    // safe by specification of ListMultimap.asMap()
    public static <K, V> Map<K, List<V>> asMap(ListMultimap<K, V> multimap);

    /**
     * SetMultimap转换为Map
     */
    @Beta
    @SuppressWarnings("unchecked")
    // safe by specification of SetMultimap.asMap()
    public static <K, V> Map<K, Set<V>> asMap(SetMultimap<K, V> multimap);

    /**
     * SortedSetMultimap转换为Map
     */
    @Beta
    @SuppressWarnings("unchecked")
    // safe by specification of SortedSetMultimap.asMap()
    public static <K, V> Map<K, SortedSet<V>> asMap(SortedSetMultimap<K, V> multimap);

    /**
     * Multimap转换为Map
     */
    @Beta
    public static <K, V> Map<K, Collection<V>> asMap(Multimap<K, V> multimap);

    /**
     * Map转换为SetMultimap
     */
    public static <K, V> SetMultimap<K, V> forMap(Map<K, V> map);

    /**
     * 对Value值做转换
     */
    public static <K, V1, V2> Multimap<K, V2> transformValues(
            Multimap<K, V1> fromMultimap, final Function<? super V1, V2> function);
    public static <K, V1, V2> ListMultimap<K, V2> transformValues(
            ListMultimap<K, V1> fromMultimap, final Function<? super V1, V2> function);

    /**
     * 对Entry值做转换
     */
    public static <K, V1, V2> Multimap<K, V2> transformEntries(
            Multimap<K, V1> fromMap, EntryTransformer<? super K, ? super V1, V2> transformer);
    public static <K, V1, V2> ListMultimap<K, V2> transformEntries(
            ListMultimap<K, V1> fromMap, EntryTransformer<? super K, ? super V1, V2> transformer);

    /**
     *
     * 按照共同的特定属性,组装成ImmutableListMultimap
     *
     * ImmutableSet digits = ImmutableSet.of("zero", "one", "two", "three", "four", "five", "six", "seven", "eight", "nine");
     * Function<String, Integer> lengthFunction = new Function<String, Integer>() {
     *     public Integer apply(String string) {
     *         return string.length();
     *     }
     * };
     *
     * ImmutableListMultimap<Integer, String> digitsByLength= Multimaps.index(digits, lengthFunction);
     * /*
     * *  digitsByLength maps:
     * *  3 => {"one", "two", "six"}
     * *  4 => {"zero", "four", "five", "nine"}
     * *  5 => {"three", "seven", "eight"}
     *
     */
    public static <K, V> ImmutableListMultimap<K, V> index(
            Iterable<V> values, Function<? super V, K> keyFunction);
    public static <K, V> ImmutableListMultimap<K, V> index(
            Iterator<V> values, Function<? super V, K> keyFunction);


    /**
     * 根据key过滤
     */
    public static <K, V> SetMultimap<K, V> filterKeys(
            SetMultimap<K, V> unfiltered, final Predicate<? super K> keyPredicate);
    public static <K, V> ListMultimap<K, V> filterKeys(
            ListMultimap<K, V> unfiltered, final Predicate<? super K> keyPredicate);

    /**
     * 根据值过滤
     */
    public static <K, V> Multimap<K, V> filterValues(
            Multimap<K, V> unfiltered, final Predicate<? super V> valuePredicate);
    public static <K, V> SetMultimap<K, V> filterValues(
            SetMultimap<K, V> unfiltered, final Predicate<? super V> valuePredicate);

    /**
     * 根据Entry过滤
     */
    public static <K, V> Multimap<K, V> filterEntries(
            Multimap<K, V> unfiltered, Predicate<? super Entry<K, V>> entryPredicate);
    public static <K, V> SetMultimap<K, V> filterEntries(
            SetMultimap<K, V> unfiltered, Predicate<? super Entry<K, V>> entryPredicate);
}

3.9 Tables

public final class Tables {

    /**
     * 用于生成一个Collector,T代表流中的一个一个元素,R代表最终的结果。参考Collector.of()的实现
     */
    @Beta
    public static <T, R, C, V, I extends Table<R, C, V>> Collector<T, ?, I> toTable(
            java.util.function.Function<? super T, ? extends R> rowFunction,
            java.util.function.Function<? super T, ? extends C> columnFunction,
            java.util.function.Function<? super T, ? extends V> valueFunction,
            java.util.function.Supplier<I> tableSupplier);
    public static <T, R, C, V, I extends Table<R, C, V>> Collector<T, ?, I> toTable(
            java.util.function.Function<? super T, ? extends R> rowFunction,
            java.util.function.Function<? super T, ? extends C> columnFunction,
            java.util.function.Function<? super T, ? extends V> valueFunction,
            BinaryOperator<V> mergeFunction,
            java.util.function.Supplier<I> tableSupplier);

    /**
     * 生成一个单元格对象
     */
    public static <R, C, V> Cell<R, C, V> immutableCell(
            @Nullable R rowKey, @Nullable C columnKey, @Nullable V value);

    /**
     * 允许你把Table<C, R, V>转置成Table<R, C, V
     */
    public static <R, C, V> Table<C, R, V> transpose(Table<R, C, V> table);

    /**
     * 允许你指定Table用什么样的map实现行和列
     */
    @Beta
    public static <R, C, V> Table<R, C, V> newCustomTable(
            Map<R, Map<C, V>> backingMap, Supplier<? extends Map<C, V>> factory);

    /**
     * 对value做转换
     */
    @Beta
    public static <R, C, V1, V2> Table<R, C, V2> transformValues(
            Table<R, C, V1> fromTable, Function<? super V1, V2> function);


    /**
     * 返回不可修改的Table
     */
    public static <R, C, V> Table<R, C, V> unmodifiableTable(
            Table<? extends R, ? extends C, ? extends V> table);

    /**
     * 生成不可修改的RowSortedTable
     */
    @Beta
    public static <R, C, V> RowSortedTable<R, C, V> unmodifiableRowSortedTable(
            RowSortedTable<R, ? extends C, ? extends V> table);



    /**
     * 生成同步Table -- 线程安全
     */
    public static <R, C, V> Table<R, C, V> synchronizedTable(Table<R, C, V> table);

}

四 扩展工具类

       有时候你需要实现自己的集合扩展。也许你想要在元素被添加到列表时增加特定的行为,或者你想实现一个Iterable,其底层实际上是遍历数据库查询的结果集。Guava为你,也为我们自己提供了若干工具方法,以便让类似的工作变得更简单。(毕竟,我们自己也要用这些工具扩展集合框架。)

4.1 Forwarding装饰器

       针对所有类型的集合接口,Guava都提供了Forwarding抽象类以简化装饰者模式的使用。Forwarding抽象类定义了一个抽象方法:delegate(),你可以覆盖这个方法来返回被装饰对象。所有其他方法都会直接委托给delegate()。例如说:ForwardingList.get(int)实际上执行了delegate().get(int)。

       通过创建ForwardingXXX的子类并实现delegate()方法,可以选择性地覆盖子类的方法来增加装饰功能,而不需要自己委托每个方法。

我们讲的更加直接一点就是,通过delegate()返回一个委托对象,这样我们可以对委托对象的一些方法的前后做一些我们自己的操作。

       Forwarding装饰器对应的类有很多,我们随便列出几个比如:ForwardingList(托管List的一些方法)、ForwardingMap(托管Map的一些方法)、ForwardingDeque(托管Deque的一些方法)等等。

       我们以ForwardingList来举一个例子,让大家明白Forwarding装饰器的使用。自定义ListWithDefault继承ForwardingList实现一个从List里面获取数据的时候如果为空则用一个默认值代替。当然实际使用过程中,大家需要根据不同的场讲做不同的变换。

import java.util.*;
import com.google.common.collect.*;

public class ListWithDefault<E> extends ForwardingList<E> {
    final E defaultValue;
    final List<E> delegate;

    ListWithDefault(List<E> delegate, E defaultValue) {
        this.delegate = delegate;
        this.defaultValue = defaultValue;
    }
    @Override protected List delegate() {
        return delegate;
    }
    @Override public E get(int index) {
        E v = super.get(index);
        return (v == null ? defaultValue : v);
    }
    @Override public Iterator<E> iterator() {
        final Iterator<E> iter = super.iterator();
        return new ForwardingIterator<E>() {
            @Override protected Iterator<E> delegate() {
                return iter;
            }
            @Override public E next() {
                E v = super.next();
                return (v == null ? defaultValue : v); 
            }
        };
    }
}

4.2 PeekingIterator

       Iterators提供一个Iterators.peekingIterator(Iterator)方法,来把Iterator包装为PeekingIterator,这是Iterator的子类,它能让你事先窥视[peek()]到下一次调用next()返回的元素。

PeekingIterator相对Iterator多了一个函数peek()函数。peek()让我们可以提前看到下一个元素。

       关于PeekingIterator的使用举个例子,复制一个List,并去除连续的重复元素。

List<E> result = Lists.newArrayList();
PeekingIterator<E> iter = Iterators.peekingIterator(source.iterator());
while (iter.hasNext()) {
    E current = iter.next();
    while (iter.hasNext() && iter.peek().equals(current)) {
        //跳过重复的元素
        iter.next();
    }
    result.add(current);
}

4.3 AbstractIterator

       实现你自己的Iterator,AbstractIterator提供了一个abstract computeNext()函数,让我们可以介入next()函数的获取。当然到没有元素的时候记得调用endOfData();

       关于AbstractIterator的使用,我们也从网上找到一个例子,如下,我们要包装一个iterator以跳过空值。

public static Iterator<String> skipNulls(final Iterator<String> in) {
    return new AbstractIterator<String>() {
        protected String computeNext() {
            while (in.hasNext()) {
                String s = in.next();
                if (s != null) {
                    return s;
                }
            }
            return endOfData();
        }
    };
}

4.5 AbstractSequentialIterator

       AbstractSequentialIterator可以看做是迭代器的另一种实现方式。AbstractSequentialIterator的源码也很简单,我们可以一起来看下,源码如下

public abstract class AbstractSequentialIterator<T> extends UnmodifiableIterator<T> {
    private @Nullable T nextOrNull;

    /**
     * 我们需要提供第一个元素
     */
    protected AbstractSequentialIterator(@Nullable T firstOrNull) {
        this.nextOrNull = firstOrNull;
    }

    /**
     * 我们需要实现的方法
     */
    @Nullable
    protected abstract T computeNext(T previous);

    /**
     * 是否有下一个元素
     */
    @Override
    public final boolean hasNext() {
        return nextOrNull != null;
    }

    /**
     * 在调用next()方法获取next元素之后,又通过computeNext()方法把接下来的一个元素给算出来了
     */
    @Override
    public final T next() {
        if (!hasNext()) {
            throw new NoSuchElementException();
        }
        try {
            return nextOrNull;
        } finally {
            nextOrNull = computeNext(nextOrNull);
        }
    }
}

       通过源码的阅读,AbstractSequentialIterator给到我们的就是通过指定第一个元素之后,我们在根据computeNext()函数依据某种规则产生下一个元素。

       我们用一个例子来说明AbstractSequentialIterator的使用,每一个数都是前一个数的两倍。

        Iterator<Integer> powersOfTwo = new AbstractSequentialIterator<Integer>(1) { // 注意初始值1!
            protected Integer computeNext(Integer previous) {
                // 下一个数是前数的两倍,一直到2的3次方
                return (previous == 1 << 3) ? null : previous * 2;
            }
        };

标签:Map,Google,final,Set,static,Collections,Guava,public,Iterable
来源: https://blog.csdn.net/wuyuxing24/article/details/100594173

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有