概述

在Java中,遍历一个List是一项常见的操作,但在遍历过程中向其中添加元素需要谨慎处理以避免异常并确保代码的正确性。本教程将讨论几种在迭代过程中向集合添加元素的方法。

1. 利用ListIterator

一种常用方法是使用ListIterator,它为列表提供了双向遍历和修改功能。

1.1. 字符串场景

假设我们要在遇到“Python”后向编程语言列表中添加“JavaScript”:

List<String> programmingLanguages = new ArrayList<>(List.of("Java", "Python", "C++"));

@Test
public void givenList_whenAddElementWithListIterator_thenModifiedList() {
    ListIterator<String> listIterator = programmingLanguages.listIterator();
    while (listIterator.hasNext()) {
        String language = listIterator.next();
        if (language.equals("Python")) {
            listIterator.add("JavaScript");
        }
    }
    assertIterableEquals(Arrays.asList("Java", "Python", "JavaScript", "C++"), programmingLanguages);
}

在给定的代码中,我们初始化了一个名为programmingLanguages的列表,包含字符串“Java”、“Python”和“C++”。使用listIterator.next()方法遍历列表元素。当我们遇到“Python”时,使用listIterator.add("JavaScript")动态地在其后插入字符串“JavaScript”。

最后的测试断言修改后的列表与预期结果匹配,确保“JavaScript”成功添加到列表中,紧跟在“Python”后面。

1.2. 数字场景

让我们将ListIterator方法应用于整数列表,当遇到数字2时,将值乘以2:

List<Integer> numbers = new ArrayList<>(List.of(1, 2, 3));
@Test
public void givenNumericalList_whenMultiplyElementWithListIterator_thenModifiedList() {
    ListIterator<Integer> listIterator = numbers.listIterator();
    while (listIterator.hasNext()) {
        int num = listIterator.next();
        if (num == 2) {
            listIterator.add(num * 10);
        }
    }
    assertIterableEquals(Arrays.asList(1, 2, 20, 3), numbers);
}

在这个数字场景中,我们使用ListIterator遍历整数列表。当遇到数字2时,值会乘以10并动态添加到列表中。

2. 使用增强for循环及副本

另一种策略是创建原始列表的副本并在修改原始列表的同时遍历副本。

2.1. 字符串场景

考虑以下示例,我们在原始列表中添加每个单词的大写版本到列表本身:

@Test
public void givenStringList_whenAddElementWithEnhancedForLoopAndCopy_thenModifiedList() {
    List<String> copyOfWords = new ArrayList<>(programmingLanguages);
    for (String word : copyOfWords) {
        programmingLanguages.add(word.toUpperCase());
    }
    assertIterableEquals(Arrays.asList("Java", "Python", "C++", "JAVA", "PYTHON", "C++"), programmingLanguages);
}

在增强for循环中,我们遍历copyOfWords列表中的每个元素,将对应的值转换为大写,并将其添加到programmingLanguages列表中。这种方法确保了原始列表在添加新内容的同时保持顺序完整性,即programmingLanguages列表将包含原始元素及其新增的大写版本。

2.2. 数字场景

现在,我们将增强for循环方法应用于整数列表,将每个数字乘以2:

List<Integer> numbers = new ArrayList<>(List.of(1, 2, 3));

@Test
public void givenList_whenAddElementWithEnhancedForLoopAndCopy_thenModifiedList() {
    List<Integer> copyOfNumbers = new ArrayList<>(numbers);
    for (int num : copyOfNumbers) {
        numbers.add(num * 2);
    }
    assertIterableEquals(Arrays.asList(1, 2, 3, 2, 4, 6), numbers);
}

在这个数字示例中,我们遍历、乘以2并将结果添加到原始列表中,与字符串方法相同。

3. 使用Java 8流式API

Java 8的流式API提供了一种简洁的方式来在迭代过程中向列表添加元素。

3.1. 字符串场景

考虑以下示例,我们使用Java 8流来向programmingLanguages列表添加“JavaScript”:

@Test
public void givenStringList_whenConvertToUpperCaseWithJava8Stream_thenModifiedList() {
    programmingLanguages = programmingLanguages.stream().map(String::toUpperCase).collect(Collectors.toList());
    assertIterableEquals(Arrays.asList("JAVA", "PYTHON", "C++"), programmingLanguages);
}

在这段代码片段中,我们利用map操作将列表中的每个字符串元素转换为其大写形式,使用toUpperCase方法。然后,通过Collectors.toList()收集转换后的元素到一个新的列表中。

请注意,虽然看起来流操作似乎直接在列表中就地修改对应元素,但实际上它替换了一个新的列表。这保证了列表内容的完整性,但原始列表的引用可能会被移除。

因此,尽管转换过程无缝进行,但必须考虑到代码其他部分可能需要原始列表的情况。

3.2. 数字场景

让我们应用Java 8流式API到整数列表,将每个数字乘以3:

@Test
public void givenNumericalList_whenMultiplyByThreeWithJava8Stream_thenModifiedList() {
    numbers = numbers.stream().map(num -> num * 3).collect(Collectors.toList());
    assertIterableEquals(Arrays.asList(3, 6, 9), numbers);
}

在这个测试方法中,我们使用map操作,对列表中的每个数字元素进行乘以3的变换,并通过Collectors.toList()将结果收集到新列表中。

4. 总结

总之,我们探讨了包括ListIterator、增强for循环副本以及Java 8流式API在内的多种方法,用于在Java中在迭代过程中向列表添加元素。

如往常一样,相关的源代码可以在GitHub上找到。