ArrayList 源码笔记

发布于:2022-12-26 ⋅ 阅读:(540) ⋅ 点赞:(0)

ArrayList 中的成员变量

elementData

ArrayList 数据存储在该数组中

transient Object[] elementData;

下文中 “数组” 一词指的就是 elementData

sizie

ArrayList 包含的元素个数

不是 elementData 的 length

private int size;

DEFAULT_CAPACITY

数组的默认初始容量大小。使用无参构造创建 ArrayList 时数组的默认容量

需要注意的的是,使用无参构造创建 ArrayList 后,只有当第一次往列表中添加元素时才会将数组容量扩容至 DEFAULT_CAPACITY

private static final int DEFAULT_CAPACITY = 10;

DEFAULTCAPACITY_EMPTY_ELEMENTDATA

用于默认大小空实例的共享空数组实例

private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};

通俗讲就是:使用无参构造创建 ArrayList 时,elementData 的赋值

new ArrayList()

EMPTY_ELEMENTDATA

用于空实例的共享空数组实例。

private static final Object[] EMPTY_ELEMENTDATA = {};

通俗讲就是:使用有参构造创建 ArrayList 时,传入初始容量为 0 时,elementData 的赋值

new ArrayList(0)

MAX_ARRAY_SIZE

elementData 数组最大容量

private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;

预留 8 个比特,因为有些虚拟机会在数组中保存对象头信息

ArrayList 的构造器

无参构造

无参数构造直接将空数组 DEFAULTCAPACITY_EMPTY_ELEMENTDATA 赋值给 elementData

/**
 * Constructs an empty list with an initial capacity of ten.
 */
public ArrayList() {
    this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}

Q: 为什么源码注释中说构造一个长度为 10 的列表,而代码却是将空数组赋值给了 elementData ?

A: 使用无参构造创建 ArrayList 后,只有当第一次往列表中添加元素时才会将数组容量扩容至 10 ( DEFAULT_CAPACITY )

有参数构造 :指定初始容量

该构造器传入参数 initialCapacity ,指定 ArrayList 的初始容量

/**
 * Constructs an empty list with the specified initial capacity.
 *
 * @param  initialCapacity  the initial capacity of the list
 * @throws IllegalArgumentException if the specified initial capacity is negative
 */
public ArrayList(int initialCapacity) {
    
    if (initialCapacity > 0) {
        // 如果传入初始容量大于 0,elementData 赋值为指定容量的数组
        this.elementData = new Object[initialCapacity];
        
    } else if (initialCapacity == 0) {
        // 如果传入初始容量等于 0,elementData 赋值为空数组 EMPTY_ELEMENTDATA
        this.elementData = EMPTY_ELEMENTDATA;
        
    } else {
        throw new IllegalArgumentException("Illegal Capacity: "+
                                           initialCapacity);
    }
}

有参数构造:包含指定集合元素

构造一个包含指定集合元素的列表,按集合的迭代器返回元素的顺序排列

/**
 * Constructs a list containing the elements of the specified
 * collection, in the order they are returned by the collection's
 * iterator.
 *
 * @param c the collection whose elements are to be placed into this list
 * @throws NullPointerException if the specified collection is null
 */
public ArrayList(Collection<? extends E> c) {
    // 将指定集合转为数组
    Object[] a = c.toArray();
    
    if ((size = a.length) != 0) {
        // 指定集合非空集合
        if (c.getClass() == ArrayList.class) {
            elementData = a;
        } else {
            elementData = Arrays.copyOf(a, size, Object[].class);
        }
    } else {
        // 传入的指定集合为空集合,elementData 赋值空数组 EMPTY_ELEMENTDATA
        elementData = EMPTY_ELEMENTDATA;
    }
}

添加元素 add() 和扩容解析

public boolean add(E e) {
    // 确保内部容量,需要时会进行扩容
    ensureCapacityInternal(size + 1); 
    
    // 赋值
    elementData[size++] = e;
    return true;
}

add() 方法中,首先调用了 ensureCapacityInternal()方法,其作用是确保内部容量: 将当前用于存储 elementData 容量和执行 add() 方法后所需要的最小容量(size + 1, 即 ArrayList 元素个数 + 1)进行比较,判断是否需要扩容

查看 ensureCapacityInternal() 方法源码

private void ensureCapacityInternal(int minCapacity) {
    ensureExplicitCapacity(
        calculateCapacity(elementData, minCapacity)
    );
}

ensureCapacityInternal() 方法中,调用了两个方法:

  • calculateCapacity() : 计算所需要的最小容量

    private static int calculateCapacity(Object[] elementData, int minCapacity) {
        /**
         * 若 elementData 为空数组 DEFAULTCAPACITY_EMPTY_ELEMENTDATA
         * 则最小需要空间至少为 DEFAULT_CAPACITY
         */
        if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
            return Math.max(DEFAULT_CAPACITY, minCapacity);
        }
        
        // 否则直接返回 minCapacity
        return minCapacity;
    }
    

    承接上文:使用无参构造创建 ArrayList 后,elementData 赋值为 DEFAULTCAPACITY_EMPTY_ELEMENTDATA

    当第一次往列表中添加元素时,才会将数组容量扩容至 10 ( DEFAULT_CAPACITY )

  • ensureExplicitCapacity() : 判断是否需要对 elementData() 进行扩容

    private void ensureExplicitCapacity(int minCapacity) {
        // 操作数 ++
        modCount++;
    
        // 若最小需要容量大于当前 elementData 容量,则进行扩容
        if (minCapacity - elementData.length > 0)
            grow(minCapacity);
    }
    

扩容方法 grow()

private void grow(int minCapacity) {
    // 旧容量: elementData 容量
    int oldCapacity = elementData.length;

    // 新容量: 旧容量的 1.5 倍
    int newCapacity = oldCapacity + (oldCapacity >> 1);

    // 新容量不满足最小所属容量,则新容量为最小所属容量
    if (newCapacity - minCapacity < 0)
        newCapacity = minCapacity;

    // 新容量大于最大容量,进入 hugeCapacity() 方法计算新容量
    if (newCapacity - MAX_ARRAY_SIZE > 0)
        newCapacity = hugeCapacity(minCapacity);

    // 将数据拷贝到新数组,并重新赋值
    elementData = Arrays.copyOf(elementData, newCapacity);
}

private static int hugeCapacity(int minCapacity) {
    if (minCapacity < 0) // overflow
        throw new OutOfMemoryError();

    // 最小所需容量大于最大容量,则新容量则为 Integer.MAX_VALUE,否则为 MAX_ARRAY_SIZE ()
    return (minCapacity > MAX_ARRAY_SIZE) ?
        Integer.MAX_VALUE :
    MAX_ARRAY_SIZE;
}

add() 的重载

在指定的位置插入指定的元素,并将后续元素往右移 (下标 + 1)

 /**
 * Inserts the specified element at the specified position in this
 * list. Shifts the element currently at that position (if any) and
 * any subsequent elements to the right (adds one to their indices).
 *
 * @param index index at which the specified element is to be inserted
 * @param element element to be inserted
 * @throws IndexOutOfBoundsException {@inheritDoc}
 */
public void add(int index, E element) {
    // 检查 index 是否合法
    rangeCheckForAdd(index);
	
    // 确保内部容量,需要时会进行扩容
    ensureCapacityInternal(size + 1);  // Increments modCount!!
    
    // 将指定位置原元素及其后续元素往右移
    System.arraycopy(elementData, index, elementData, index + 1, size - index);
    
    // 指定位置赋值
    elementData[index] = element;
    size++;
}

private void rangeCheckForAdd(int index) {
    if (index > size || index < 0)
        throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
}

System.arraycopy()

一个本地方法,其作用是将一个数组中指定范围的元素 复制到指定数组中

/**
 * 
 * @param src 		源数组
 * @param srcPos 	源数组中的起始下标
 * @param dest 		目标数组
 * @param destPos 	目标数组中的起始下标
 * @param length 	需要复制的元素的个数
 */
public static native void arraycopy(Object src,  int  srcPos,
                                    Object dest, int destPos,
                                    int length);

批量添加元素 addAll()

将指定集合中的所有元素追加到 ArrayList 末尾

    /**
     * Appends all of the elements in the specified collection to the end of
     * this list, in the order that they are returned by the
     * specified collection's Iterator.  The behavior of this operation is
     * undefined if the specified collection is modified while the operation
     * is in progress.  (This implies that the behavior of this call is
     * undefined if the specified collection is this list, and this
     * list is nonempty.)
     *
     * @param c collection containing elements to be added to this list
     * @return <tt>true</tt> if this list changed as a result of the call
     * @throws NullPointerException if the specified collection is null
     */
    public boolean addAll(Collection<? extends E> c) {
        // 将指定集合转数组
        Object[] a = c.toArray();
        
        // 确保内部容量,需要时会进行扩容
        int numNew = a.length;
        ensureCapacityInternal(size + numNew);  // Increments modCount
        
        // 拷贝数组
        System.arraycopy(a, 0, elementData, size, numNew);
        size += numNew;
        return numNew != 0;
    }

​ 从 ArrayList 的指定位置开始,将指定集合中的所有元素插入到 ArrayList 中。并将原来位于该位置的元素(如果有)和所有后续元素向右移动(增加它们的索引)

/**
     * Inserts all of the elements in the specified collection into this
     * list, starting at the specified position.  Shifts the element
     * currently at that position (if any) and any subsequent elements to
     * the right (increases their indices).  The new elements will appear
     * in the list in the order that they are returned by the
     * specified collection's iterator.
     *
     * @param index index at which to insert the first element from the
     *              specified collection
     * @param c collection containing elements to be added to this list
     * @return <tt>true</tt> if this list changed as a result of the call
     * @throws IndexOutOfBoundsException {@inheritDoc}
     * @throws NullPointerException if the specified collection is null
     */
    public boolean addAll(int index, Collection<? extends E> c) {
        // 检查索引合法性
        rangeCheckForAdd(index);
		
        // 将指定集合转数组
        Object[] a = c.toArray();
        
        // 确保内部容量,需要时会进行扩容
        int numNew = a.length;
        ensureCapacityInternal(size + numNew);  // Increments modCount

        // 将原来位于 index 位置的元素(如果有)和所有后续元素右移
        int numMoved = size - index;
        if (numMoved > 0)
            System.arraycopy(elementData, index, elementData, index + numNew,
                             numMoved);
		
        // 插入指定集合元素
        System.arraycopy(a, 0, elementData, index, numNew);
        size += numNew;
        return numNew != 0;
    }

获取元素get()

获取 ArrayList 指定位置元素

/**
 * Returns the element at the specified position in this list.
 *
 * @param  index index of the element to return
 * @return the element at the specified position in this list
 * @throws IndexOutOfBoundsException {@inheritDoc}
 */
public E get(int index) {
    // 检查下标志是否合法
    rangeCheck(index);

    // 返回指定位置元素
    return elementData(index);
}

private void rangeCheck(int index) {
    if (index >= size)
        throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
}

替换元素 set()

替换 ArrayList 中指定位置的元素

/**
 * Replaces the element at the specified position in this list with
 * the specified element.
 *
 * @param index index of the element to replace
 * @param element element to be stored at the specified position
 * @return the element previously at the specified position
 * @throws IndexOutOfBoundsException {@inheritDoc}
 */
public E set(int index, E element) {
    // 检查下标值合法性
    rangeCheck(index);
	
    // 保存旧值
    E oldValue = elementData(index);
    
    // 替换新值
    elementData[index] = element;
    
    // 返回旧值
    return oldValue;
}

删除元素 remove()

删除指定下标元素

/**
 * Removes the element at the specified position in this list.
 * Shifts any subsequent elements to the left (subtracts one from their
 * indices).
 *
 * @param index the index of the element to be removed
 * @return the element that was removed from the list
 * @throws IndexOutOfBoundsException {@inheritDoc}
 */
public E remove(int index) {
    // 检查下标值合法性
    rangeCheck(index);

    // 操作数 ++
    modCount++;
    
    // 保存即将被删除的元素
    E oldValue = elementData(index);

    // 左移后续元素
    int numMoved = size - index - 1;
    if (numMoved > 0)
        System.arraycopy(elementData, index+1, elementData, index,
                         numMoved);
    elementData[--size] = null; // clear to let GC do its work

    // 返回被删除的元素
    return oldValue;
}

从列表中删除第一个出现的指定元素,如果不存在则列表不变

    /**
     * Removes the first occurrence of the specified element from this list,
     * if it is present.  If the list does not contain the element, it is
     * unchanged.  More formally, removes the element with the lowest index
     * <tt>i</tt> such that
     * <tt>(o==null&nbsp;?&nbsp;get(i)==null&nbsp;:&nbsp;o.equals(get(i)))</tt>
     * (if such an element exists).  Returns <tt>true</tt> if this list
     * contained the specified element (or equivalently, if this list
     * changed as a result of the call).
     *
     * @param o element to be removed from this list, if present
     * @return <tt>true</tt> if this list contained the specified element
     */
    public boolean remove(Object o) {
        if (o == null) {
            for (int index = 0; index < size; index++)
                if (elementData[index] == null) {
                    fastRemove(index);
                    return true;
                }
        } else {
            for (int index = 0; index < size; index++)
                if (o.equals(elementData[index])) {
                    fastRemove(index);
                    return true;
                }
        }
        return false;
    }

fastRemove()

跳过边界检查直接删除元素

/*
 * Private remove method that skips bounds checking and does not
 * return the value removed.
 */
private void fastRemove(int index) {
    // 操作数 ++
    modCount++;
    
    // 删除元素,并左移后续元素
    int numMoved = size - index - 1;
    if (numMoved > 0)
        System.arraycopy(elementData, index+1, elementData, index,
                         numMoved);
    elementData[--size] = null; // clear to let GC do its work
}

批量删除元素 removeAll()

从 ArrayList 中移除指定集合中包含的所有元素。

    /**
     * Removes from this list all of its elements that are contained in the
     * specified collection.
     *
     * @param c collection containing elements to be removed from this list
     * @return {@code true} if this list changed as a result of the call
     * @throws ClassCastException if the class of an element of this list
     *         is incompatible with the specified collection
     * (<a href="Collection.html#optional-restrictions">optional</a>)
     * @throws NullPointerException if this list contains a null element and the
     *         specified collection does not permit null elements
     * (<a href="Collection.html#optional-restrictions">optional</a>),
     *         or if the specified collection is null
     * @see Collection#contains(Object)
     */
    public boolean removeAll(Collection<?> c) {
        // 校验传入参数是否为 null,为 null 抛出异常
        Objects.requireNonNull(c);
        
        // 移除元素
        return batchRemove(c, false);
    }

保留指定元素 retainAll()

从 ArrayList 中删除指定集合中不包含的所有元素

    /**
     * Retains only the elements in this list that are contained in the
     * specified collection.  In other words, removes from this list all
     * of its elements that are not contained in the specified collection.
     *
     * @param c collection containing elements to be retained in this list
     * @return {@code true} if this list changed as a result of the call
     * @throws ClassCastException if the class of an element of this list
     *         is incompatible with the specified collection
     * (<a href="Collection.html#optional-restrictions">optional</a>)
     * @throws NullPointerException if this list contains a null element and the
     *         specified collection does not permit null elements
     * (<a href="Collection.html#optional-restrictions">optional</a>),
     *         or if the specified collection is null
     * @see Collection#contains(Object)
     */
    public boolean retainAll(Collection<?> c) {
        // 校验传入参数是否为 null,为 null 抛出异常
        Objects.requireNonNull(c);
        
        // 移除元素
        return batchRemove(c, true);
    }

集合排序 sort()

    @Override
    @SuppressWarnings("unchecked")
    public void sort(Comparator<? super E> c) {
        // 期望操作数
        final int expectedModCount = modCount;
        
        // 调用 Arrays.sort() 方法进行排序
        Arrays.sort((E[]) elementData, 0, size, c);
        
      	// 当前操作数与期望操作数不一致,快速失败(fail-fast)机制抛出并发修改异常
        if (modCount != expectedModCount) {
            throw new ConcurrentModificationException();
        }
        
        // 操作数 ++
        modCount++;
    }

子列表视图 subList()

ArrayList的**subList()(它返回原来 list 的从 [fromIndex, toIndex) 之间这一部分的视图)**结果不可强转成ArrayList

因为该方法返回的是 ArrayList 的内部类 SubList , 并不是一个List而是一个视图,对 subList 的所有操作最终会反映到原列表上

public List<E> subList(int fromIndex, int toIndex) {
    subListRangeCheck(fromIndex, toIndex, size);
    return new SubList(this, 0, fromIndex, toIndex);
}

static void subListRangeCheck(int fromIndex, int toIndex, int size) {
    if (fromIndex < 0)
        throw new IndexOutOfBoundsException("fromIndex = " + fromIndex);
    if (toIndex > size)
        throw new IndexOutOfBoundsException("toIndex = " + toIndex);
    if (fromIndex > toIndex)
        throw new IllegalArgumentException("fromIndex(" + fromIndex +
                                           ") > toIndex(" + toIndex + ")");
}

清空列表 clear()

删除 ArrayList 中所有元素

    /**
     * Removes all of the elements from this list.  The list will
     * be empty after this call returns.
     */
    public void clear() {
        // 操作数 ++
        modCount++;

        // elementData 中所有值置 null,让 GC 回收
        for (int i = 0; i < size; i++)
            elementData[i] = null;
		
        // 元素个数设置 0
        size = 0;
    }

获取元素个数 size()

public int size() {
    return size;
}

判断空列表 isEmpty()

public boolean isEmpty() {
        return size == 0;
    }

获取列表中第一个匹配的元素下标 indexOf()

获取列表中第一个匹配元素的下标值,若无匹配元素则返回 -1

    /**
     * Returns the index of the first occurrence of the specified element
     * in this list, or -1 if this list does not contain the element.
     * More formally, returns the lowest index <tt>i</tt> such that
     * <tt>(o==null&nbsp;?&nbsp;get(i)==null&nbsp;:&nbsp;o.equals(get(i)))</tt>,
     * or -1 if there is no such index.
     */
    public int indexOf(Object o) {
        if (o == null) {
            for (int i = 0; i < size; i++)
                if (elementData[i]==null)
                    return i;
        } else {
            for (int i = 0; i < size; i++)
                if (o.equals(elementData[i]))
                    return i;
        }
        return -1;
    }

获取列表中最后一个匹配的元素下标 lastIndexOf()

返回指定元素最后一次出现的下标值,若无匹配元素则返回 -1

    /**
     * Returns the index of the last occurrence of the specified element
     * in this list, or -1 if this list does not contain the element.
     * More formally, returns the highest index <tt>i</tt> such that
     * <tt>(o==null&nbsp;?&nbsp;get(i)==null&nbsp;:&nbsp;o.equals(get(i)))</tt>,
     * or -1 if there is no such index.
     */
    public int lastIndexOf(Object o) {
        if (o == null) {
            for (int i = size-1; i >= 0; i--)
                if (elementData[i]==null)
                    return i;
        } else {
            for (int i = size-1; i >= 0; i--)
                if (o.equals(elementData[i]))
                    return i;
        }
        return -1;
    }

是否包含指定元素 contains()

public boolean contains(Object o) {
    return indexOf(o) >= 0;
}

修剪列表 trimToSize()

将ArrayList 实例的容量 (即 elementData 容量) 修剪为 列表的当前大小(size)

应用程序可以使用此操作最小化 ArrayList 实例的存储

    /**
     * Trims the capacity of this <tt>ArrayList</tt> instance to be the
     * list's current size.  An application can use this operation to minimize
     * the storage of an <tt>ArrayList</tt> instance.
     */
    public void trimToSize() {
        modCount++;
        if (size < elementData.length) {
            elementData = (size == 0)
              ? EMPTY_ELEMENTDATA
              : Arrays.copyOf(elementData, size);
        }
    }

设置实际容量 ensureCapacity()

如果需要,增加这个 ArrayList 实例的容量,以确保它至少可以容纳最小容量参数指定的元素数量。

在往 ArrayList 添加大量元素之前,可以使用该方法设置容量,减少多次扩容带来的开销

    /**
     * Increases the capacity of this <tt>ArrayList</tt> instance, if
     * necessary, to ensure that it can hold at least the number of elements
     * specified by the minimum capacity argument.
     *
     * @param   minCapacity   the desired minimum capacity
     */
    public void ensureCapacity(int minCapacity) {
        int minExpand = (elementData != DEFAULTCAPACITY_EMPTY_ELEMENTDATA) ? 0 : DEFAULT_CAPACITY;

        if (minCapacity > minExpand) {
            ensureExplicitCapacity(minCapacity);
        }
    }

浅拷贝 clone()

ArrayList 实现了 Cloneable 接口,覆盖了克隆方法 clone(),能被克隆

clone 方法返回 ArrayList 实例的浅拷贝副本

ArrayList 的浅拷贝:只拷贝元素的引用,不拷贝元素本身

	/**
     * Returns a shallow copy of this <tt>ArrayList</tt> instance.  (The
     * elements themselves are not copied.)
     *
     * @return a clone of this <tt>ArrayList</tt> instance
     */
    public Object clone() {
        try {
            ArrayList<?> v = (ArrayList<?>) super.clone();
            v.elementData = Arrays.copyOf(elementData, size);
            v.modCount = 0;
            return v;
        } catch (CloneNotSupportedException e) {
            // this shouldn't happen, since we are Cloneable
            throw new InternalError(e);
        }
    }

集合转数组 toArray()

返回 ArrayList 中所有元素的数组

	public Object[] toArray() {
        return Arrays.copyOf(elementData, size);
    }

	public <T> T[] toArray(T[] a) {
        if (a.length < size)
            // Make a new array of a's runtime type, but my contents:
            return (T[]) Arrays.copyOf(elementData, size, a.getClass());
        System.arraycopy(elementData, 0, a, 0, size);
        if (a.length > size)
            a[size] = null;
        return a;
    }

阿里开发规范:使用集合转数组必须使用集合的toArray(T[] array),传入的是类型完全一致,长度为0 的空数组(直接使用 toArray 无参方法存在问题,此方法返回值只能是 Object[]类,若强转其它类型数组将出现错误)

list.toArray(new Long[0])

过滤集合 removeIf()

条件过滤集合

    @Override
    public boolean removeIf(Predicate<? super E> filter) {
        Objects.requireNonNull(filter);
        // figure out which elements are to be removed
        // any exception thrown from the filter predicate at this stage
        // will leave the collection unmodified
        int removeCount = 0;
        final BitSet removeSet = new BitSet(size);
        final int expectedModCount = modCount;
        final int size = this.size;
        for (int i=0; modCount == expectedModCount && i < size; i++) {
            @SuppressWarnings("unchecked")
            final E element = (E) elementData[i];
            if (filter.test(element)) {
                removeSet.set(i);
                removeCount++;
            }
        }
        if (modCount != expectedModCount) {
            throw new ConcurrentModificationException();
        }

        // shift surviving elements left over the spaces left by removed elements
        final boolean anyToRemove = removeCount > 0;
        if (anyToRemove) {
            final int newSize = size - removeCount;
            for (int i=0, j=0; (i < size) && (j < newSize); i++, j++) {
                i = removeSet.nextClearBit(i);
                elementData[j] = elementData[i];
            }
            for (int k=newSize; k < size; k++) {
                elementData[k] = null;  // Let gc do its work
            }
            this.size = newSize;
            if (modCount != expectedModCount) {
                throw new ConcurrentModificationException();
            }
            modCount++;
        }

        return anyToRemove;
    }

示例

// 用户列表筛选管理员
list.removeIf(user -> user.isAdmin());

替换所有元素 replaceAll()

replaceAll() 方法用于将给定的操作内容替换掉数组中每一个元素

    @Override
    @SuppressWarnings("unchecked")
    public void replaceAll(UnaryOperator<E> operator) {
        // 校验传入参数非空
        Objects.requireNonNull(operator);
        
        // 期望操作数
        final int expectedModCount = modCount;
        
        // 遍历集合,按照传入的规则对元素操作
        final int size = this.size;
        for (int i=0; modCount == expectedModCount && i < size; i++) {
            elementData[i] = operator.apply((E) elementData[i]);
        }
        
        // 当前操作数与期望操作数不一致,快速失败(fail-fast)机制抛出并发修改异常
        if (modCount != expectedModCount) {
            throw new ConcurrentModificationException();
        }
        
        modCount++;
    }

示例

       List<String> list = new ArrayList<>();
       list.add("abc");
       list.add("xyz");
       list.add("cnm");
       
		// 转大写
       list.replaceAll(s -> s.toUpperCase());
本文含有隐藏内容,请 开通VIP 后查看

网站公告

今日签到

点亮在社区的每一天
去签到