如何自定义JEXL函数实现集合过滤?Lambda表达式解析遇阻
解决JEXL自定义集合Filter函数的Lambda表达式解析问题
JEXL本身并不原生支持你写的'a -> a.age > 10'这种字符串形式的Lambda语法作为参数传递,直接使用会触发解析错误或未定义变量问题——因为JEXL会把这个字符串当作普通文本,不会自动解析为可执行的表达式。下面是可行的实现方案:
核心思路
自定义filter函数时,手动解析传入的Lambda字符串,提取条件表达式和参数名,再逐个遍历集合元素,将元素放入JEXL上下文后执行条件判断。
实现步骤
1. 编写自定义集合工具类
这个类里的filter方法负责处理集合和Lambda条件字符串:
import org.apache.commons.jexl3.*; import java.util.ArrayList; import java.util.List; import java.util.regex.Matcher; import java.util.regex.Pattern; public class JexlCollectionUtils { // 初始化JEXL引擎 private static final JexlEngine JEXL_ENGINE = new JexlBuilder().create(); // 匹配Lambda格式的正则:匹配 变量名 -> 条件表达式 private static final Pattern LAMBDA_PATTERN = Pattern.compile("^\\s*(\\w+)\\s*->\\s*(.*)$"); public static <T> List<T> filter(List<T> collection, String lambdaStr) { List<T> filteredList = new ArrayList<>(); JexlContext context = new MapContext(); // 解析Lambda字符串 Matcher matcher = LAMBDA_PATTERN.matcher(lambdaStr); String varName; String conditionExpr; if (matcher.matches()) { varName = matcher.group(1); // 提取Lambda参数名(比如a) conditionExpr = matcher.group(2); // 提取条件表达式(比如a.age > 10) } else { // 兼容直接传入条件表达式的情况,默认用item作为变量名 varName = "item"; conditionExpr = lambdaStr; } JexlExpression expr = JEXL_ENGINE.createExpression(conditionExpr); // 遍历集合,逐个判断条件 for (T item : collection) { context.set(varName, item); Object result = expr.evaluate(context); // 执行结果为true则加入结果集 if (result instanceof Boolean && (Boolean) result) { filteredList.add(item); } } return filteredList; } }
2. 注册工具类到JEXL上下文
将工具类实例放入JEXL上下文,让表达式可以调用:
import org.apache.commons.jexl3.JexlContext; import org.apache.commons.jexl3.MapContext; import java.util.List; // 假设你的Person实体类 class Person { private String name; private int age; public Person(String name, int age) { this.name = name; this.age = age; } // Getter方法 public String getName() { return name; } public int getAge() { return age; } } public class Main { public static void main(String[] args) { // 构造测试数据 List<Person> persons = List.of( new Person("Alice", 8), new Person("Bob", 12), new Person("Charlie", 15) ); // 初始化JEXL上下文 JexlContext context = new MapContext(); context.set("collections", persons); context.set("utils", new JexlCollectionUtils()); // 注册工具类 // 执行你想要的表达式 JexlEngine jexl = new JexlBuilder().create(); JexlExpression filterExpr = jexl.createExpression("utils.filter(collections, 'a -> a.age > 10')"); List<Person> result = (List<Person>) filterExpr.evaluate(context); // 输出结果 result.forEach(p -> System.out.println(p.getName())); // 输出Bob、Charlie } }
常见问题排查
- 未定义变量错误:之前的写法中,JEXL没有将字符串里的
a识别为上下文变量,因为它只是字符串的一部分——本方案通过手动将集合元素设置为上下文变量解决了这个问题。 - 解析错误:JEXL不支持原生的
a -> ...语法,本方案通过正则提取条件表达式,避免了直接解析Lambda语法的问题。 - 版本兼容:确保使用JEXL 3.x版本,旧版本API可能存在差异。
内容的提问来源于stack exchange,提问作者user2103145
相关产品推荐
相关产品推荐

