Skip to content

内联列表 (Inline Lists)

可以使用 {} 标记法在表达式中直接表示列表。

java
// 评估结果为一个包含四个数字的 Java List
List numbers = (List) parser.parseExpression("{1,2,3,4}").getValue(context);

// 嵌套列表
List listOfLists = (List) parser.parseExpression("{{'a','b'},{'x','y'}}").getValue(context);
kotlin
// 评估结果为一个包含四个数字的 Java List
val numbers = parser.parseExpression("{1,2,3,4}").getValue(context) as List<*>

// 嵌套列表
val listOfLists = parser.parseExpression("{{'a','b'},{'x','y'}}").getValue(context) as List<*>

单独的 {} 表示一个空列表。出于性能原因,如果列表本身完全由固定字面量组成,则会创建一个常量列表来表示该表达式(而不是在每次评估时都构建一个新列表)。


补充教学

1. 为什么不用 new ArrayList()

在 SpEL 中,{1,2,3} 是一种更加声明式的语法,就像 Python 的 [1,2,3]。它不仅代码更短,而且语义更清晰。它生成的底层对象通常是不可变列表(或者为了性能进行了特殊优化的列表)。

2. 常见应用场景:权限与过滤

你最常在 Spring Security 的注解中见到这种语法:

  • 角色检查@PreAuthorize("hasAnyRole({'ROLE_ADMIN', 'ROLE_USER'})")
  • 默认值补全:在 @Value 中初始化一个列表:
    java
    @Value("#{{'standard', 'premium', 'vip'}}")
    private List<String> accountTypes;

3. 注意事项:与 JSON 的区别

虽然 {} 看起来像 JSON 的对象,但在 SpEL 中:

  • {} 是列表 (List)
  • {key:value} 才是映射 (Map)(详见下一章“内联 Map”)。 不要因为习惯了 JSON 语法而在这里产生混淆。

4. 性能优化:重复执行的开销

正如官方文档提到的,如果你写的是字面量列表(如 {'A', 'B'}),Spring 会在解析阶段就将其“冻结”为一个常量。这意味着如果你在一个高频调用的方法(如循环处理 10 万行数据)中使用这个表达式,它不会创建 10 万个 List 对象,这极大地减轻了垃圾回收 (GC) 的压力。

Based on Spring Framework.