核心是用包装类对象和类型约束从源头隔离非法字符串:声明泛型集合、封装键值校验、采用不可变容器、预过滤null、自定义安全容器内聚转换逻辑。

核心不是“用什么数据结构”,而是让数据结构承载经过校验的包装类对象,从源头隔离非法字符串。集合本身不解决转换问题,但选对类型、配好约束、配合安全转换逻辑,就能把报错挡在运行前。
用泛型明确集合元素类型,杜绝混入非数字对象
避免使用 ArrayList 或原始类型集合,它们会在运行时才暴露类型问题:
- 声明时锁定为 ArrayList
:确保所有元素都是字符串,后续统一走安全解析流程 - 若需混合存储(如带标识的数值),不用 Object,改用封装类:record DataPoint(String key, String value) {},再存入 List
- 接收外部集合参数时,优先调用 List.copyOf(input),防止调用方中途篡改内部元素类型
用不可变/线程安全容器承接转换结果,避免 null 拆箱雷区
转换后的包装类(如 Integer)可能为 null,直接遍历或算术操作极易触发 NullPointerException:
- 不推荐:for (Integer x : list) { sum += x; } —— 若 list 含 null,立刻崩
- 推荐用 Stream 预过滤:list.stream().filter(Objects::nonNull).mapToInt(Integer::intValue).sum()
- 多线程写入场景下,用 ConcurrentLinkedQueue
或 CopyOnWriteArrayList ,避免手动加锁和 null 竞态
用 Map + 包装类做键值校验,规避误转与类型错位
从 JSON、配置文件或数据库读取键值对时,“123”可能是 String,也可能是 Long,不能盲目强转:
- 先判断实际类型:if (obj instanceof String s && isNumeric(s)) { return Integer.valueOf(s); }
- 若 obj 是 Number 类型(如 Long、BigDecimal),优先调用 number.intValue(),而非强制转 String 再 parse
- 对 Map
,不要写 (Integer) map.get("age"),应封装工具方法:getInteger(map, "age", -1),内部做类型判断+安全 fallback
用自定义容器替代裸集合,把校验逻辑内聚进去
把“字符串→数字”的规则和默认策略封装进一个轻量类,比到处调工具方法更可控:
- 定义 NumericList:构造时接受 String[],内部用 safeParseInt(s, null) 批量转,只存非 null 的 Integer
- 提供 asIntStream() 方法,返回已 filter(null) 的 IntStream,供计算复用
- 重写 toString() 时自动跳过 null 元素,避免日志打印时报 NPE











