Guava源码解析九:Lists源码解析

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/dancheng1/article/details/85253162

构造方法

private Lists() {
}

私有的构造方法,可以看到这是一个真正的功能函数,下面对其函数进行分析

 

功能函数

首先根据每一个函数的更能进行了分类:

创建ArrayList方法

newArrayList()

newArrayList(E... elements)

newArrayList(Iterable<? extends E> elements)

newArrayList(Iterator<? extends E> elements)

newArrayListWithCapacity(int initialArraySize)

newArrayListWithExpectedSize(int estimatedSize)

创建LinkedList方法

newLinkedList()

newLinkedList(Iterable<? extends E> elements)

创建CopyOnWriteArrayList方法

newCopyOnWriteArrayList()

newCopyOnWriteArrayList(Iterable<? extends E> elements)

创建自制List规则

asList(@Nullable E first, E[] rest)

asList(@Nullable E first, @Nullable E second, E[] rest)

对多个List做笛卡尔乘积

cartesianProduct(List<? extends List<? extends B>> lists)

cartesianProduct(List<? extends B>... lists)

从做个类型的List转到另一个类型的List方法

transform(List<F> fromList, Function<? super F, ? extends T> function)

对list进行分批输出的方法(作用之一:分页)

partition(List<T> list, int size)

将字符串作为字符数组进行操作

charactersOf(String string)

charactersOf(CharSequence sequence)

将list逆序

reverse(List<T> list)

 

下面对每一类进行源码解析:

创建ArrayList方法

  1. 没有参数的创建ArrayList
public static <E> ArrayList<E> newArrayList() {
    return new ArrayList();
}

查看源码可以看到,直接返回一个新的ArrayList容器

 

  1. 传入一个数组,返回一个ArrayList
public static <E> ArrayList<E> newArrayList(E... elements) {
    //对数组进行判空处理
    Preconditions.checkNotNull(elements);
    // computeArrayListCapacity对当前数量进行优化
    int capacity = computeArrayListCapacity(elements.length);
    //这里根据优化后的数量进行创建一个新的ArrayList
    ArrayList list = new ArrayList(capacity);
    //将数组里面的元素都存储在List中
    Collections.addAll(list, elements);
    return list;
}

有上面,我们可以解析一下computeArrayListCapacity方法:

static int computeArrayListCapacity(int arraySize) {
    //判断是否小于0,小于0则抛出异常
    CollectPreconditions.checkNonnegative(arraySize, "arraySize");
    // saturatedCast函数判断计算出来的数组长度是否在int的范围内
    return Ints.saturatedCast(5L + (long)arraySize + (long)(arraySize / 10));
}

可以看到对于传入的数值进行运算:5L+arraysize+(arraysize/10)

可以拿一个10长度的数组进行测试,优化后的list长度为16

优点:节约内存,节约时间,节约性能。代码质量提高

saturatedCast函数的源码

public static int saturatedCast(long value) {
        return value > 2147483647L?2147483647:(value < -2147483648L?-2147483648:(int)value);
}

3.传入一个集合顶级接口,然后返回一个ArrayList

public static <E> ArrayList<E> newArrayList(Iterable<? extends E> elements) {
    //对集合进行判空
    Preconditions.checkNotNull(elements);
    //根据传入的实际类型,进行分别处理
    return elements instanceof Collection?new ArrayList(Collections2.cast(elements)):newArrayList((Iterator)elements.
iterator());
}

4.传入一个迭代器,返回一个ArrayList

public static <E> ArrayList<E> newArrayList(Iterator<? extends E> elements) {
    ArrayList list = newArrayList();
    //根据Iterators中的addAll方法将迭代器中的源码装入list集合中
    Iterators.addAll(list, elements);
    return list;
}

最终是由Iterators中的addAll方法进行的数据转移操作

 

5.传入想要的list长度,返回一个与传入值等长的ArrayList

public static <E> ArrayList<E> newArrayListWithCapacity(int initialArraySize) {
    CollectPreconditions.checkNonnegative(initialArraySize, "initialArraySize");
    return new ArrayList(initialArraySize);
}

可以看到源码直接返回一个新的ArrayList,并且长度为传入的长度

 

6.传入一个想要的list长度,返回一个程序调优后的长度的ArrayList

public static <E> ArrayList<E> newArrayListWithExpectedSize(int estimatedSize) {
    return new ArrayList(computeArrayListCapacity(estimatedSize));
}

computeArrayListCapacity函数的计算公式上面介绍过了,这里直接返回一个长度调优后的ArrayList

 

创建LinkedList方法

  1. 不传入参数,直接返回一个LinkedList
public static <E> LinkedList<E> newLinkedList() {
    return new LinkedList();
}

如源码所示,直接返回一个LinkedList

 

  1. 传入一个容器,返回一个LinkedList
public static <E> LinkedList<E> newLinkedList(Iterable<? extends E> elements) {
    LinkedList list = newLinkedList();
    Iterables.addAll(list, elements);
    return list;
}

可以看到源码中,将传入的容器,使用Iterables的addAll方法进行的数据转移

 

创建CopyOnWriteArrayList方法

  1. 不传入参数,直接返回一个新的CopyOnWriteArrayList
public static <E> CopyOnWriteArrayList<E> newCopyOnWriteArrayList() {
    return new CopyOnWriteArrayList();
}

 

  1. 传入一个容器,返回一个CopyOnWriteArrayList,带有传入容器的值
public static <E> CopyOnWriteArrayList<E> newCopyOnWriteArrayList(Iterable<? extends E> elements) {
    Object elementsCollection = elements instanceof Collection?Collections2.cast(elements):newArrayList((Iterable)elements);
    return new CopyOnWriteArrayList((Collection)elementsCollection);
}

 

创建自制List规则

  1. 根据参数生成一个多一个参数的List
public static <E> List<E> asList(@Nullable E first, E[] rest) {
    return new Lists.OnePlusArrayList(first, rest);
}

返回一个Lists中的内部类OnePlusArrayList,下面进行解析OnePlusArrayList的源码

private static class OnePlusArrayList<E> extends AbstractList<E> implements Serializable, RandomAccess {
    final E first;
    final E[] rest;
    private static final long serialVersionUID = 0L;

    OnePlusArrayList(@Nullable E first, E[] rest) {
        this.first = first;
        this.rest = (Object[])Preconditions.checkNotNull(rest);
    }

    public int size() {
        return this.rest.length + 1;
    }

    public E get(int index) {
        Preconditions.checkElementIndex(index, this.size());
        return index == 0?this.first:this.rest[index - 1];
    }
}

可以看到OnePlusArrayList类进行重写了size和get方法。因为是比原来数组多1个数,所以size方法在原来的基础上进行了+1操作。对get的重写是将所有的下标逻辑上后移了一位。

 

  1. 根据参数生成一个多两个个参数的List
public static <E> List<E> asList(@Nullable E first, @Nullable E second, E[] rest) {
    return new Lists.TwoPlusArrayList(first, second, rest);
}

返回一个Lists中的内部类TwoPlusArrayList,下面进行解析TwoPlusArrayList的源码

private static class TwoPlusArrayList<E> extends AbstractList<E> implements Serializable, RandomAccess {
    final E first;
    final E second;
    final E[] rest;
    private static final long serialVersionUID = 0L;

    TwoPlusArrayList(@Nullable E first, @Nullable E second, E[] rest) {
        this.first = first;
        this.second = second;
        this.rest = (Object[])Preconditions.checkNotNull(rest);
    }

    public int size() {
        return this.rest.length + 2;
    }

    public E get(int index) {
        switch(index) {
        case 0:
            return this.first;
        case 1:
            return this.second;
        default:
            Preconditions.checkElementIndex(index, this.size());
            return this.rest[index - 2];
        }
    }
} 

根据源码可以看到,TwoPlusArrayList重写了size和get两个方法,size在实际数组长度上进行了+2的操作,get则在逻辑上将下标进行了后移两位

 

对多个List做笛卡尔乘积

从做个类型的List转到另一个类型的List方法

public static <F, T> List<T> transform(List<F> fromList, Function<? super F, ? extends T> function) {
    return (List)(fromList instanceof RandomAccess?new Lists.TransformingRandomAccessList(fromList, function):new Lists.TransformingSequentialList(fromList, function));
}

看源码可以知道,程序会根据传入的List属于什么类型进行分类处理,不过无论使用哪种方式进行处理,在他们的实现类中都重写了listIterator方法,下面我们主要对这个方法进行分析:

private static class TransformingRandomAccessList<F, T> extends AbstractList<T> implements RandomAccess, Serializable {
    final List<F> fromList;
    final Function<? super F, ? extends T> function;
    private static final long serialVersionUID = 0L;

    TransformingRandomAccessList(List<F> fromList, Function<? super F, ? extends T> function) {
        this.fromList = (List)Preconditions.checkNotNull(fromList);
        this.function = (Function)Preconditions.checkNotNull(function);
    }
    public ListIterator<T> listIterator(int index) {
        return new TransformedListIterator(this.fromList.listIterator(index)) {
            T transform(F from) {
                return TransformingRandomAccessList.this.function.apply(from);
            }
        };
    }
}

可以看到这个listIterator实际上就是根据传入的函数对数据进行处理的,实际上就是使用者自己对List进行转型的,这个工具只不过实现了对每一个迭代的时候使用使用者传入的函数,进行输出结果。不过根据这个源码可以看到一个坑,就是他使用的引用还是传入的那个集合的引用,如果原集合出现变化,这个集合也会跟着变的。

 

对list进行分批输出的方法(作用之一:分页)

public static <T> List<List<T>> partition(List<T> list, int size) {
    Preconditions.checkNotNull(list);
    Preconditions.checkArgument(size > 0);
    return (List)(list instanceof RandomAccess?new Lists.RandomAccessPartition(list, size):new Lists.Partition(list, size));
}

       看源码可以知道,程序根据传入的List进行分类处理,不过RandomAccessPartition是Partition的子类,且RandomAccessPartition对其的处理是直接调用了父类的方法,所以我们只需要解析Partition类就可以了:

private static class Partition<T> extends AbstractList<List<T>> {
    final List<T> list;
    final int size;
    Partition(List<T> list, int size) {
        this.list = list;
        this.size = size;
    }
    public List<T> get(int index) {
        Preconditions.checkElementIndex(index, this.size());
        int start = index * this.size;
        int end = Math.min(start + this.size, this.list.size());
        return this.list.subList(start, end);
    }
    public int size() {
        return IntMath.divide(this.list.size(), this.size, RoundingMode.CEILING);
    }
    public boolean isEmpty() {
        return this.list.isEmpty();
    }
}

它的get方法进行了截取操作,而它的截取底层是subList实现的。它所get的下标为第几组List

 

将字符串作为字符数组进行操作

public static ImmutableList<Character> charactersOf(String string) {
    return new Lists.StringAsImmutableList((String)Preconditions.checkNotNull(string));
}
public static List<Character> charactersOf(CharSequence sequence) {
    return new Lists.CharSequenceAsList((CharSequence)Preconditions.checkNotNull(sequence));
}

两个方法分别接收字符串和CharSequence作为参数,将参数传入CharSequenceAsList类中进行处理:

private static final class StringAsImmutableList extends ImmutableList<Character> {
    private final String string;

    StringAsImmutableList(String string) {
        this.string = string;
    }

    public int indexOf(@Nullable Object object) {
        return object instanceof Character?this.string.indexOf(((Character)object).charValue()):-1;
    }

    public int lastIndexOf(@Nullable Object object) {
        return object instanceof Character?this.string.lastIndexOf(((Character)object).charValue()):-1;
    }

    public ImmutableList<Character> subList(int fromIndex, int toIndex) {
        Preconditions.checkPositionIndexes(fromIndex, toIndex, this.size());
        return Lists.charactersOf((String)this.string.substring(fromIndex, toIndex));
    }

    boolean isPartialView() {
        return false;
    }

    public Character get(int index) {
        Preconditions.checkElementIndex(index, this.size());
        return Character.valueOf(this.string.charAt(index));
    }

    public int size() {
        return this.string.length();
    }
}

可以看到CharSequenceAsList类的实现实际上就是对间接使用String类中的方法进行处理字符串

 

将list逆序

public static <T> List<T> reverse(List<T> list) {
    return (List)(list instanceof ImmutableList?((ImmutableList)list).reverse():(list instanceof Lists.ReverseList?((Lists.ReverseList)list).getForwardList():(list instanceof RandomAccess?new Lists.RandomAccessReverseList(list):new Lists.ReverseList(list))));
}

可以看到这个reverse方法实际上调用了ImmutableList类的reverse方法进行处理的逆序

猜你喜欢

转载自blog.csdn.net/dancheng1/article/details/85253162