概述
本文将探讨如何将给定的ArrayList<Object>
转换为ArrayList<String>
的各种方法。
问题描述
设想我们有一个ArrayList<Object>
,其中的对象可以是任何类型,包括自动装箱的基本类型(如Integer
、Float
或Boolean
),非基本引用类型(如String
、ArrayList
、HashMap
,甚至是自定义定义的类)。我们需要编写代码,将上述列表转换为ArrayList<String>
。让我们看几个例子:
Example 1: [1, 2, 3, 4, 5]
Output 1: ["1", "2", "3", "4", "5"]
Example 2: ["Hello", 4.9837, -19837338737, true]
Output 2: ["Hello", "4.9837", "-19837338737", "true"]
Example 3: [new Node(1,4), new Double(7699.05), new User("John Doe")]
Output 3: ["Node (x=1, y=4)", "7699.05", "User (full name=John Doe)"]
输入列表可以包含各种对象,如自定义类User
和Node
的实例。假设这些类已重写了toString()
方法。如果没有定义,将调用Object
类的toString()
方法,输出如下:
Node@f6d9f0, User@u8g0f9
以上示例包含了自定义类User
和Node
的实例:
public class User {
private final String fullName;
// getters and setters
@Override
public String toString() {
return "User (" + "full name='" + fullName + ')';
}
}
public class Node {
private final int x;
private final int y;
// getters and setters
@Override
public String toString() {
return "Node (" + "x=" + x + ", y=" + y + ')';
}
}
假设在接下来的部分中,变量inputList
和expectedStringList
引用了我们的目标输入和输出列表:
List<Object> inputList = List.of(
1,
true,
"hello",
Double.valueOf(273773.98),
new Node(2, 4),
new User("John Doe")
);
List<String> expectedStringList = List.of(
"1",
"true",
"hello",
Double.toString(273773.98),
new Node(2, 4).toString(),
new User("John Doe").toString()
);
使用Java集合遍历转换
首先尝试使用Java集合来解决这个问题。思路是遍历列表中的每个元素,并将其转换为String
。完成后,我们就得到了一个String
对象的列表。下面的代码使用for-each循环遍历给定的列表,并通过调用toString()
方法明确地将每个对象转换为String
:
List<String> outputList = new ArrayList<>(inputList.size());
for(Object obj : inputList){
outputList.add(obj.toString());
}
Assert.assertEquals(expectedStringList, outputList);
这个解决方案适用于输入列表中所有对象组合,并且对所有Java版本(Java 5及以上)都有效。然而,上述解决方案无法免疫输入中的null
对象,遇到null
时会抛出NullPointerException
。一个简单的改进利用了Java 7引入的Objects
工具类提供的toString()
方法,使其对null
安全:
List<String> outputList = new ArrayList<>(inputList.size());
for(Object obj : inputList){
outputList.add(Objects.toString(obj, null));
}
Assert.assertEquals(expectedStringList, outputList);
使用Java流转换
我们也可以利用Java 8的流API来解决问题。首先,我们将数据源inputList
转换为流,通过应用stream()
方法。当我们有了一个元素类型为Object
的流后,我们需要一个中间操作,即对象到字符串的转换,最后是收集结果到另一个String
类型的列表的终端操作。
中间操作在我们的例子中是一个map()
操作,它接受一个lambda表达式:
(obj) -> Objects.toString(obj, null)
流需要一个终端操作来编译并返回所需的列表。在接下来的子节中,我们将讨论可用的不同终端操作。
4.1. Collectors.toList()
作为终端操作
在这个方法中,我们使用Collectors.toList()
将由中间操作生成的流收集到输出列表中:
List<String> outputList;
outputList = inputList
.stream()
.map((obj) -> Objects.toString(obj, null))
.collect(Collectors.toList());
Assert.assertEquals(expectedStringList, outputList);
这种方法适用于Java 8及更高版本,因为流API在Java 8中引入。输出的列表是可变的,意味着我们可以向其中添加元素。输出列表也可能包含null
值。
4.2. Collectors.toUnmodifableList()
作为终端操作 - Java 10兼容方法
如果我们想要生成一个不可修改的String
对象列表,我们可以利用Java 10中引入的Collectors.toUnmodifableList()
实现:
List<String> outputList;
outputList = inputList
.stream()
.filter(Objects::nonNull)
.map((obj) -> Objects.toString(obj, null))
.collect(Collectors.toUnmodifiableList());
Assert.assertEquals(expectedStringListWithoutNull, outputList);
这里的一个重要限制是列表不能包含null
值,因此如果inputList
包含null
,这段代码会产生NullPointerException
。这就是为什么我们在应用操作之前先从流中选择只包含非null
元素的原因。输出列表是不可变的,如果尝试后续修改,将抛出UnsupportedOperationException
。
4.3. toList()
作为终端操作 - Java 16兼容方法
如果想直接从输入流创建一个允许包含null
值的不可修改列表,可以使用Java 16中在Stream
接口中引入的toList()
方法:
List<String> outputList;
outputList = inputList
.stream()
.map((obj) -> Objects.toString(obj, null))
.toList();
Assert.assertEquals(expectedStringList, outputList);
使用Guava转换
我们可以使用Google的Guava库将对象输入列表转换为String
的新列表。
5.1. Maven配置
为了使用Guava库,我们需要在pom.xml
中添加相应的Maven依赖:
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>33.0.0-jre</version>
<scope>test</scope>
</dependency>
可以从Maven中央仓库获取最新版本的依赖。
5.2. 使用Lists.transform()
我们可以使用Guava的Lists.transform()
方法。它接受inputList
和前面提到的lambda表达式,生成String
对象的输出列表:
List<String> outputList;
outputList = Lists.transform(inputList, obj -> Objects.toString(obj, null));
Assert.assertEquals(expectedStringList, outputList);
使用此方法,输出列表可以包含null
值。
总结
本文探讨了将ArrayList<Object>
元素转换为ArrayList<String>
的几种不同方式,从基于for-each循环的方法到Java流的方法。还研究了针对不同Java版本的特定实现,以及使用Guava的方法。如往常一样,所有的代码示例可以在GitHub上找到。