问题描述:

如下代码会造成死循环

        int startI = 1;
        int endI = startI + 1;
        List<Integer> result = integerList.subList(0, 1);
        while (startI < integerList.size()) {
            List<Integer> subList = integerList.subList(startI, endI);
            result.addAll(subList);
            startI = endI;
            endI = startI + 1;
        }

 

原因:

subList函数没有创建新的对象,而是记录坐标,使用了原本的列表对象。

Java Doc 如下:

    /**
     * Returns a view of the portion of this list between the specified
     * <tt>fromIndex</tt>, inclusive, and <tt>toIndex</tt>, exclusive.  (If
     * <tt>fromIndex</tt> and <tt>toIndex</tt> are equal, the returned list is
     * empty.)  The returned list is backed by this list, so non-structural
     * changes in the returned list are reflected in this list, and vice-versa.
     * The returned list supports all of the optional list operations supported
     * by this list.<p>
     *
     * This method eliminates the need for explicit range operations (of
     * the sort that commonly exist for arrays).  Any operation that expects
     * a list can be used as a range operation by passing a subList view
     * instead of a whole list.  For example, the following idiom
     * removes a range of elements from a list:
     * <pre>{@code
     *      list.subList(from, to).clear();
     * }</pre>
     * Similar idioms may be constructed for <tt>indexOf</tt> and
     * <tt>lastIndexOf</tt>, and all of the algorithms in the
     * <tt>Collections</tt> class can be applied to a subList.<p>
     *
     * The semantics of the list returned by this method become undefined if
     * the backing list (i.e., this list) is <i>structurally modified</i> in
     * any way other than via the returned list.  (Structural modifications are
     * those that change the size of this list, or otherwise perturb it in such
     * a fashion that iterations in progress may yield incorrect results.)
     *
     * @param fromIndex low endpoint (inclusive) of the subList
     * @param toIndex high endpoint (exclusive) of the subList
     * @return a view of the specified range within this list
     * @throws IndexOutOfBoundsException for an illegal endpoint index value
     *         (<tt>fromIndex &lt; 0 || toIndex &gt; size ||
     *         fromIndex &gt; toIndex</tt>)
     */
    List<E> subList(int fromIndex, int toIndex);

 

解决方式:

写了一个比较糙的方法,如下:

    private <T> List<T> copySubList(List<T> origin, int startI, int endI) {
        List<T> subList = origin.subList(startI, endI);
        List<T> result = new ArrayList<>(subList.size());
        result.addAll(subList);
        return result;
    }

 

反思:

假设有程序员小明需要开发以上逻辑,在没有人事先提醒的情况下,小明写出死循环的概率有多大?小明自己预感到可能有问题的概率有多大?

应该有人事先提醒小明吗,应该提醒每一个“小明”吗?

应该修改subList的函数签名吗?