Java IndexOutOfBoundsException “Source Does Not Fit in Dest” – Java IndexOutOfBoundsException “Source Does Not Fit in Dest”

最后修改: 2020年 11月 9日

中文/混合/英文(键盘快捷键:t)

1. Overview

1.概述

In Java, making a copy of a List can sometimes produce an IndexOutOfBoundsException: “Source does not fit in dest”. In this short tutorial, we’re going to look at why we get this error when using the Collections.copy method and how it can be solved. We’ll also look at alternatives to Collections.copy to make a copy of the list.

在 Java 中,对 List 进行复制有时会产生一个 IndexOutOfBoundsException。”在这个简短的教程中,我们将看看为什么在使用Collections.copy方法时,我们会遇到这个错误,以及如何解决这个问题。我们还将看看Collections.copy的替代方法,以制作列表的副本。

2. Reproducing the Problem

2.重现问题

Let’s start with a method to create a copy of a List using the Collections.copy method:

让我们从使用Collections.copy方法来创建List的副本开始。

static List<Integer> copyList(List<Integer> source) {
    List<Integer> destination = new ArrayList<>(source.size());
    Collections.copy(destination, source);
    return destination;
}

Here, the copyList method creates a new list with an initial capacity equal to the size of the source list. Then it tries to copy the elements of the source list to the destination list:

在这里,copyList方法创建了一个新的列表,其初始容量与源列表的大小相等。然后它试图将源列表中的元素复制到目标列表中。

List<Integer> source = Arrays.asList(1, 2, 3, 4, 5);
List<Integer> copy = copyList(source);

However, once we make a call to the copyList method, it throws an exception java.lang.IndexOutOfBoundsException: Source does not fit in dest.

然而,一旦我们对copyList方法进行调用,它就会抛出一个异常java.lang.IndexOutOfBoundsException。来源不适合在目的地

3. Cause of the Exception

3.导致异常的原因

Let’s try to understand what went wrong. According to the documentation for the Collections.copy method:

让我们试着了解一下哪里出了问题。根据Collections.copy方法的文档。

The destination list must be at least as long as the source list. If it’s longer, the remaining elements in the destination list are unaffected.

目标列表必须至少和源列表一样长。如果它更长,目标列表中的其余元素不受影响。

In our example, we’ve created a new List using a constructor with an initial capacity equal to the size of the source list. It simply allocates enough memory and doesn’t actually define elements. The size of the new list remains zero because the capacity and the size are different attributes of the List.

在我们的例子中,我们使用一个构造函数创建了一个新的 List,其初始容量等于源列表的大小。它只是分配了足够的内存,并没有实际定义元素。新列表的大小仍然为零,因为容量和大小是List的不同属性。

Therefore, when the Collections.copy method tries to copy the source list into the destination list, it throws java.lang.IndexOutOfBoundsException.

因此,当Collections.copy方法试图将源列表复制到目标列表时,它会抛出java.lang.IndexOutOfBoundsException.

4. Solutions

4.解决方案

4.1. Collections.copy

4.1.Collections.copy

Let’s look at a working example to copy a List to another List, using the Collections.copy method:

让我们看一个工作例子,使用Collections.copy方法,将一个List复制到另一个List

List<Integer> destination = Arrays.asList(1, 2, 3, 4, 5);
List<Integer> source = Arrays.asList(11, 22, 33);
Collections.copy(destination, source);

In this case, we’re copying all three elements of the source list to the destination list. The Arrays.asList method initializes the list with elements and not just a size, therefore, we’re able to copy the source list to the destination list successfully.

在这种情况下,我们要把源列表的所有三个元素复制到目标列表中。Arrays.asList 方法用元素而不仅仅是大小来初始化列表,因此,我们能够成功地将源列表复制到目标列表中。

If we just swap the arguments of the Collections.copy method, it will throw java.lang.IndexOutOfBoundsException because the size of the source list is less than the size of the destination list.

如果我们只是交换Collections.copy方法的参数,它将抛出java.lang.IndexOutOfBoundsException,因为源列表的大小小于目标列表的大小

After this copy operation, the destination list looks like:

在这个复制操作之后,目的地列表看起来像。

[11, 22, 33, 4, 5]

Along with the Collections.copy method, there are other ways in Java to make a copy of List. Let’s take a look at some of them.

除了Collections.copy方法外,在Java中还有其他方法来复制List。让我们来看看其中的一些。

4.2. ArrayList Constructor

4.2.ArrayList构造函数

The simplest approach to copy a List is using a constructor that takes a Collection parameter:

复制List的最简单方法是使用一个接受Collection参数的constructor

List<Integer> source = Arrays.asList(11, 22, 33);
List<Integer> destination = new ArrayList<>(source);

Here, we simply pass the source list to the constructor of the destination list, which creates a shallow copy of the source list.

在这里,我们简单地将源列表传递给目标列表的构造函数,该函数创建了源列表的浅层拷贝。

The destination list will be just another reference to the same object referenced by the source list. So, every change made by any reference will affect the same object.

目标列表将只是对源列表所引用的同一对象的另一个引用。因此,任何引用所做的每一个改变都会影响到同一个对象。

Therefore, using a constructor is a good option for copying immutable objects like Integers and Strings.

因此,使用构造函数是复制像IntegersStrings.这样的不可变对象的一个好选择。

4.3. addAll

4.3.addAll

Another simple way is to use the addAll method of List:

另一个简单的方法是使用addAllList方法。

List<Integer> destination = new ArrayList<>();
destination.addAll(source);

The addAll method will copy all the elements of the source list to the destination list.

addAll 方法将把源列表的所有元素复制到目标列表。

There are a couple of points to note regarding this approach:

关于这种方法,有几个要点需要注意。

  1. It creates a shallow copy of the source list.
  2. The elements of the source list are appended to the destination list.

4.4. Java 8 Streams

4.4 Java 8的

Java 8 has introduced the Stream API, which is a great tool for working with Java Collections.

Java 8引入了Stream API,它是使用Java Collections的一个伟大工具。

Using the stream() method, we make a copy of the list using Stream API:

使用stream()方法,我们使用Stream API:制作一个列表的副本。

List<Integer> copy = source.stream()
  .collect(Collectors.toList());

4.5. Java 10

4.5 Java 10

Copying a List is even simpler in Java 10. Using the copyOf() method allows us to create an immutable list containing the elements of the given Collection:

复制 List 在 Java 10 中更加简单。使用copyOf()方法,我们可以创建一个包含给定Collection元素的不可变列表。

List<Integer> destination = List.copyOf(sourceList);

If we want to go with this approach, we need to make sure the input List isn’t null and that it doesn’t contain any null elements.

如果我们想采用这种方法,我们需要确保输入的List 不是null,并且它不包含任何null元素。

5. Conclusion

5.总结

In this article, we looked at how and why the Collections.copy method throws IndexOutOfBoundException “Source does not file in dest”. Along with it, we also explored different ways to copy a List to another List.

在这篇文章中,我们研究了Collections.copy方法如何以及为什么会抛出IndexOutOfBoundException “Source does not file in dest” 。同时,我们还探讨了将一个List复制到另一个List.的不同方法。

Both the pre-Java-10 examples and the Java 10 examples can be found over on GitHub.

pre-Java-10 示例Java 10 示例都可以在 GitHub 上找到。