Java中如何将可能为数组或Collection的对象转为指定格式字符串?
问题背景
入参为Object类型,实际可能是Collection实例、Object[]引用类型数组、任意基本类型数组,需要统一输出[e1, e2, ..., en]格式的字符串,要求优先无第三方依赖,尽量避免冗长的多分支类型判断。现有实现存在以下缺陷:
String.valueOf(object);:无法正确处理数组,也不能兼容重写了非标准toString()的第三方Collection实现object.getClass().isArray() ? Arrays.toString((Object[]) object) : String.valueOf(object);:传入基本类型数组时会抛出ClassCastException,因为基本类型数组无法强转为Object[]"[" + Stream.of(object).map(v -> v.toString()).collect(Collectors.joining(", ")) + "]";:Stream.of会把非数组入参整体作为单个元素生成流,也无法正确遍历基本类型数组、集合的内容
最优实现
核心思路是先把不同类型的入参统一转换为元素流,再统一完成字符串拼接,从根源避免多分支重复处理格式逻辑,纯JDK原生API实现:
import java.lang.reflect.Array; import java.util.Collection; import java.util.stream.Collectors; import java.util.stream.Stream; public class ListFormatUtil { public static String format(Object obj) { if (obj == null) { return "null"; } Class<?> objClass = obj.getClass(); Stream<?> elements; if (objClass.isArray()) { // 反射接口统一处理所有数组类型,无需单独判断8种基本类型数组 elements = Stream.iterate(0, i -> i + 1) .limit(Array.getLength(obj)) .map(idx -> Array.get(obj, idx)); } else if (obj instanceof Collection<?>) { // 手动遍历集合元素,不依赖集合自身toString实现,规避第三方集合自定义toString的格式偏差 elements = ((Collection<?>) obj).stream(); } else { elements = Stream.of(obj); } return elements.map(String::valueOf) .collect(Collectors.joining(", ", "[", "]")); } }
方案说明
- 代码分支极短:仅做2次类型判断,没有冗余的switch/if-else枚举所有基本数组类型,维护成本低
- 无任何第三方依赖,适配所有JDK8及以上版本
- 完全规避现有方案的所有问题:
- 集合类型不依赖自身
toString实现,不管第三方集合怎么重写toString,都按遍历元素的规则输出统一格式 - 数组通过
java.lang.reflect.Array的原生API操作,基本类型数组取值时会自动装箱为对应包装类型,不会出现类型转换异常 - 所有场景都会先拆解为单个元素流再拼接,不会出现把整个数组/集合当成单个元素处理的问题
- 集合类型不依赖自身
- 性能表现:反射操作数组的开销极低,和直接遍历数组的性能差距在纳秒级别,远低于字符串拼接本身的消耗,常规业务场景下完全没有性能瓶颈
如果需要支持嵌套集合、嵌套数组的格式化,只需要把map步骤的String::valueOf替换为递归调用format方法即可;当前默认实现和JDK内置Arrays.toString行为保持一致,直接输出元素自身的字符串表示。
内容的提问来源于stack exchange,提问作者xtay2
相关产品推荐
相关产品推荐

