如何在Xtend的Iterable过滤函数中传入多类型参数减少样板代码?
解决Xtext生成器中多类型过滤的样板代码问题
针对你遇到的重复嵌套循环问题,完全可以通过几种方式合并成单个循环,大幅减少样板代码。下面是几种实用的解决方案,适配Xtext/EMF的场景:
方案1:直接用instanceof多条件过滤(Java 8+)
利用Stream的filter方法,在条件中直接判断元素是否属于目标类型之一,然后统一处理:
for (IfStatements ifStatement : ifElseStatement.eAllContents.toIterable().filter(IfStatements)) { ifStatement.expression.eAllContents.toIterable() .stream() .filter(element -> element instanceof SingleLibraryPersistenceMethodStatement || element instanceof SingleLibraryInterFaceMethodStatement || element instanceof SingleLibraryBusinessMethodStatement || element instanceof RelationalOperator ) .forEach(element -> { // 如果getDemand是重载方法,Java会自动匹配对应类型;如果是统一接受父类,直接传即可 expressionDemand += getDemand(element, resourceTable); }); }
方案2:提取目标类型集合,动态检查(更易维护)
如果后续可能需要新增类型,把目标类型放到集合中,通过anyMatch判断元素是否属于其中之一:
// 提前定义目标类型集合(可以放到类的常量里复用) private static final Set<Class<?>> TARGET_METHOD_TYPES = Set.of( SingleLibraryPersistenceMethodStatement.class, SingleLibraryInterFaceMethodStatement.class, SingleLibraryBusinessMethodStatement.class, RelationalOperator.class ); // 业务代码中使用 for (IfStatements ifStatement : ifElseStatement.eAllContents.toIterable().filter(IfStatements)) { ifStatement.expression.eAllContents.toIterable() .stream() .filter(element -> TARGET_METHOD_TYPES.stream().anyMatch(type -> type.isInstance(element))) .forEach(element -> expressionDemand += getDemand(element, resourceTable)); }
方案3:利用EMF原生EClass判断(更贴合Xtext场景)
因为你的DSL模型是EMF生成的,每个类型都对应一个EClass,用EMF的类型体系判断更准确(比如处理继承场景):
// 从你的DSL包中获取对应的EClass常量 private static final Set<EClass> TARGET_ECLASSES = Set.of( YourDslPackage.Literals.SINGLE_LIBRARY_PERSISTENCE_METHOD_STATEMENT, YourDslPackage.Literals.SINGLE_LIBRARY_INTER_FACE_METHOD_STATEMENT, YourDslPackage.Literals.SINGLE_LIBRARY_BUSINESS_METHOD_STATEMENT, YourDslPackage.Literals.RELATIONAL_OPERATOR ); // 业务代码中使用 for (IfStatements ifStatement : ifElseStatement.eAllContents.toIterable().filter(IfStatements)) { ifStatement.expression.eAllContents.toIterable() .stream() .filter(element -> TARGET_ECLASSES.contains(element.eClass())) .forEach(element -> expressionDemand += getDemand(element, resourceTable)); }
方案4:Java 16+ 模式匹配(处理重载的getDemand)
如果你的getDemand是重载方法(每个类型对应一个实现),可以用Java 16+的instanceof模式匹配,直接在forEach中处理类型转换和调用:
for (IfStatements ifStatement : ifElseStatement.eAllContents.toIterable().filter(IfStatements)) { ifStatement.expression.eAllContents.toIterable() .forEach(element -> { if (element instanceof SingleLibraryPersistenceMethodStatement p) { expressionDemand += getDemand(p, resourceTable); } else if (element instanceof SingleLibraryInterFaceMethodStatement i) { expressionDemand += getDemand(i, resourceTable); } else if (element instanceof SingleLibraryBusinessMethodStatement b) { expressionDemand += getDemand(b, resourceTable); } else if (element instanceof RelationalOperator r) { expressionDemand += getDemand(r, resourceTable); } }); }
这种方式把过滤和方法调用合并到一个逻辑块,完全消除了重复的循环结构。
以上几种方案都能有效减少样板代码,你可以根据自己的Java版本、代码维护习惯选择最合适的方式。
内容的提问来源于stack exchange,提问作者Jos B.
相关产品推荐
相关产品推荐

