场景
Expression exp = spelParser.parseExpression("#{#avgTable?.get(2)?.get(0)}", new TemplateParserContext());
String _result = exp.getValue(evalContext, String.class);
当avgTable?.get(2)为空时,Method threw 'java.lang.IndexOutOfBoundsException' exception.
在 Spring Expression Language (SpEL) 中,安全导航操作符 (?.
) 通常可以防止 NullPointerException
,但如果它不起作用,可能是以下原因导致的:
1. ?.
无法防止 IndexOutOfBoundsException
问题原因:
avgTable?.get(2)
如果avgTable
是List
且size() <= 2
,会抛出IndexOutOfBoundsException
,而不是返回null
。?.
只能防止NullPointerException
(即avgTable
为null
的情况),但无法阻止越界访问。
解决方案:
- 改用
size()
检查:"#{(#avgTable != null && #avgTable.size() > 2) ? #avgTable.get(2)?.get(0) : null}"
- 或使用
SafeList
包装(自定义方法,返回null
而不是抛异常)。
2. SpEL 版本或解析方式问题
问题原因:
- 某些旧版本的 SpEL 可能对
?.
支持不完全。 - 如果使用的是
TemplateParserContext
(如#{...}
),确保语法正确。
解决方案:
- 升级 Spring 版本(推荐 Spring 5+)。
- 检查 SpEL 表达式是否正确解析:
Expression exp = parser.parseExpression("#{#avgTable?.get(2)?.get(0)}", new TemplateParserContext());
3. avgTable
不是标准的 Java Bean/List/Map
问题原因:
- 如果
avgTable
是自定义类,且get(2)
不是标准方法(如数组访问或特殊数据结构),?.
可能不会按预期工作。 - 例如,数组访问
arr[2]
越界会直接抛异常,?.
无法阻止。
解决方案:
- 改用
List
或Map
结构。 - 或手动检查索引:
"#{(#avgTable != null && #avgTable.length > 2) ? #avgTable[2]?.property : null}"
4. 嵌套对象访问方式错误
问题原因:
- 如果
avgTable.get(2)
返回的对象没有get(0)
方法,?.
也无法阻止NoSuchMethodException
。 - 例如:
List<String> row = avgTable.get(2); // 返回 String,但尝试调用 get(0) row?.get(0); // String 没有 get(0) 方法,会抛异常
解决方案:
- 确保对象结构正确:
"#{#avgTable?.get(2) instanceof List ? #avgTable.get(2)?.get(0) : null}"
5. 表达式解析错误
问题原因:
- 如果 SpEL 表达式语法错误(如括号不匹配),
?.
可能不会生效。 - 例如:
"#{#avgTable?.get(2)?.get(0}" // 缺少右括号
解决方案:
- 检查表达式语法是否正确:
"#{#avgTable?.get(2)?.get(0)}" // 正确
推荐解决方案
1. 使用 size()
检查索引(适用于 List
)
Expression exp = parser.parseExpression(
"#{(#avgTable != null && #avgTable.size() > 2) ? #avgTable.get(2)?.get(0) : null}",
new TemplateParserContext()
);
2. 使用 Elvis 运算符提供默认值
Expression exp = parser.parseExpression(
"#{#avgTable?.get(2)?.get(0) ?: 'DEFAULT'}",
new TemplateParserContext()
);
3. 使用 try-catch
(不推荐,仅备用)
Expression exp = parser.parseExpression(
"#{T(org.springframework.util.ObjectUtils).nullSafeToString(#avgTable?.get(2)?.get(0))}",
new TemplateParserContext()
);
总结
问题 | 原因 | 解决方案 |
---|---|---|
IndexOutOfBoundsException | List.get(2) 越界 | 检查 size() |
NullPointerException | avgTable 为 null | 使用 ?. |
自定义类无 get(0) | 对象结构错误 | 检查类型 |
SpEL 语法错误 | 表达式不合法 | 修复语法 |
旧版 SpEL 问题 | 版本兼容性 | 升级 Spring |
如果仍然有问题,建议打印 avgTable
的实际类型和结构:
System.out.println("avgTable class: " + avgTable.getClass());
System.out.println("avgTable size: " + (avgTable != null ? avgTable.size() : "null"));
这样可以更精准地定位问题。