1. 概述
在Java编程中,操作列表是基础技能之一。
本快速教程将介绍几种修改或转换列表的方法,并演示如何在Java中打印其元素。
2. 修改并打印列表
打印列表元素对我们来说并不困难。例如,我们可以使用forEach()
方法调用打印动作:
List<String> theList = Lists.newArrayList("Kai", "Liam", "Eric", "Kevin");
theList.forEach(element -> log.info(element));
在这段代码中,我们使用了SLF4J日志器输出给定列表中的元素。执行代码后,我们在控制台能看到四个名字:
Kai
Liam
Eric
Kevin
如果我们打算在打印之前修改列表中的元素,可以利用List.replaceAll()
方法:
接下来,让我们在测试方法中将theList
中的每个String
元素转换为大写,然后打印修改后的值:
List<String> theList = Lists.newArrayList("Kai", "Liam", "Eric", "Kevin");
theList.replaceAll(element -> element.toUpperCase());
theList.forEach(element -> log.info(element));
assertEquals(List.of("KAI", "LIAM", "ERIC", "KEVIN"), theList);
如图所示,我们在replaceAll()
方法中使用了一个lambda表达式来执行大小写转换。运行测试后,我们能在控制台看到大写值:
KAI
LIAM
ERIC
KEVIN
需要注意的是,replaceAll()
方法要求列表对象是可变的,如上述代码中使用的ArrayList
。如果列表是不可变的,比如由Collections.singletonList()
和List.of()
返回的对象,该方法会抛出UnsupportedOperationException
。
因此,在实际场景中,通常更倾向于将原始列表转换为新的列表,而不是直接修改它。接下来,我们将探讨如何高效地转换列表并流畅地输出其元素。
3. 使用流API转换并打印列表
Java 8引入的流API(Stream API)极大地改变了我们处理对象集合的方式。流提供了一种声明式和函数式的数据处理方法,为对集合进行操作提供了简洁且表达性强的方式。
例如,我们可以从列表开始,使用map()
方法对流中的元素进行变换,然后使用forEachOrdered()
打印元素,如下所示:
theList.stream()
.map(... <the transformation logic> ...)
.forEachOrdered( ... <print the element> ...)
这段代码相当直观。但重要的是要注意,Stream.forEachOrdered()
是一个终端操作。这个终端操作本质上标志着流的管道结束。因此,调用此方法后,流对象就无法访问了。这意味着后续的流操作,如收集变换后的元素,不再可行。
因此,我们希望通过不同的方式实现目标,允许我们在流上继续执行操作。
一个简单的方法是在map()
中包含打印方法的调用:
List<String> theList = List.of("Kai", "Liam", "Eric", "Kevin");
List<String> newList = theList.stream()
.map(element -> {
String newElement = element.toUpperCase();
log.info(newElement);
return newElement;
})
.collect(Collectors.toList());
assertEquals(List.of("KAI", "LIAM", "ERIC", "KEVIN"), newList);
这样,打印流并不会终止流的管道,我们仍可以在之后进行如collect()
这样的操作。当然,变换后的元素会被打印到控制台:
KAI
LIAM
ERIC
KEVIN
然而,这种方法的一个缺点是,它在map()
方法中不必要地添加了无关的逻辑。接下来,我们可以使用peek()
方法来改进它:
List<String> theList = List.of("Kai", "Liam", "Eric", "Kevin");
List<String> newList = theList.stream()
.map(element -> element.toUpperCase())
.peek(element -> log.info(element))
.collect(Collectors.toList());
assertEquals(List.of("KAI", "LIAM", "ERIC", "KEVIN"), newList);
与forEachOrdered()
不同,peek()
是一个中间操作。它对流中的每个元素执行提供的操作并返回流。因此,我们在调用peek()
后,还可以在流管道中添加更多的操作,如上述代码中的collect()
。
peek()
方法接受一个Consumer
实例作为参数。在我们的示例中,我们将一个lambda表达式作为Consumer
传递给了peek()
。
当运行这个测试时,它通过了,预期的输出被打印到控制台:
KAI
LIAM
ERIC
KEVIN
4. 总结
本文首先展示了如何使用replaceAll()
+ forEach()
方法修改并打印列表。接着,我们探讨了如何使用流API来转换并打印流中的元素。
如往常一样,示例代码的完整源码可在GitHub上找到。