Java lambda 即使在第二次调用时也保留第一次调用的外部参数值
Java lambda keeps outer param value of first call even on second call
标题可能描述性不强,但我会尝试恢复我的问题。
因此,我正在尝试使用 Java 规范创建动态查询。在我的例子中,带有过滤器的 DTO 来自 REST 端点,对于每个过滤器,我都试图创建一个这样的规范:
private Specification<TrafficData> buildSpecificationQuery(TrafficDataRequestDTO requestDTO) {
List<Specification<TrafficData>> specificationList = new ArrayList<>();
requestDTO.getFilters().forEach(filter -> {
specificationList.add(createSpecification(filter));
});
Specification<TrafficData> specification = Specification.where(specificationList.remove(0));
specificationList.forEach(specification::and);
return specification;
}
private Specification<TrafficData> createSpecification(final TrafficDataFilterDTO input) {
switch (input.getOperator()) {
case EQUALS:
return (root, query, criteriaBuilder) -> criteriaBuilder.equal(root.get(input.getFieldName()), input.getValue());
case NOT_EQUALS:
return (root, query, criteriaBuilder) ->
criteriaBuilder.notEqual(root.get(input.getFieldName()), input.getValue());
case STARTS_WITH:
return (root, query, criteriaBuilder) ->
criteriaBuilder.like(root.get(input.getFieldName()), input.getValue() + "%");
case ENDS_WITH:
return (root, query, criteriaBuilder) ->
criteriaBuilder.like(root.get(input.getFieldName()), "%" + input.getValue());
case CONTAINS:
return (root, query, criteriaBuilder) ->
criteriaBuilder.like(root.get(input.getFieldName()), "%" + input.getValue() + "%");
default:
throw new RuntimeException("Operation not supported yet");
}
}
过滤器 DTO 如下所示:
@Data
public class TrafficDataFilterDTO {
private String fieldName;
private TrafficDataFilterOperator operator;
private String value;
}
奇怪的是,当我为两个不同的过滤器 object 调用此代码时,lambda 似乎只使用一个 input
值,而它 returns 我只是一个查询对于第一个标准。这一定是与 java lambda 参数相关的问题,但我不能确切地说出它是什么。
真实场景:
当我有两个不同的过滤器时 object:
{ "fieldName": "version", "operator": "EQUALS", "value": "EN_UK" }, { "fieldName": "isManaged", "operator": "EQUALS", "value": true }
方法 createSpecification(final TrafficDataFilterDTO input) 被调用两次,输入值正确(对于每个过滤器),但包含 lambda 的行
criteriaBuilder.equal(root.get(input.getFieldName()), input.getValue());
被第一个过滤器调用两次 object
等待解决方案和解释为什么会这样。
Specificiation.and()
returns 一个新的 Specification
因此您加入规范的代码不起作用。
您需要加入这样的规范:
Specification<TrafficData> specification = Specification.where(specificationList.remove(0));
return specificationList.stream().reduce(specification, Specification::and);
标题可能描述性不强,但我会尝试恢复我的问题。
因此,我正在尝试使用 Java 规范创建动态查询。在我的例子中,带有过滤器的 DTO 来自 REST 端点,对于每个过滤器,我都试图创建一个这样的规范:
private Specification<TrafficData> buildSpecificationQuery(TrafficDataRequestDTO requestDTO) {
List<Specification<TrafficData>> specificationList = new ArrayList<>();
requestDTO.getFilters().forEach(filter -> {
specificationList.add(createSpecification(filter));
});
Specification<TrafficData> specification = Specification.where(specificationList.remove(0));
specificationList.forEach(specification::and);
return specification;
}
private Specification<TrafficData> createSpecification(final TrafficDataFilterDTO input) {
switch (input.getOperator()) {
case EQUALS:
return (root, query, criteriaBuilder) -> criteriaBuilder.equal(root.get(input.getFieldName()), input.getValue());
case NOT_EQUALS:
return (root, query, criteriaBuilder) ->
criteriaBuilder.notEqual(root.get(input.getFieldName()), input.getValue());
case STARTS_WITH:
return (root, query, criteriaBuilder) ->
criteriaBuilder.like(root.get(input.getFieldName()), input.getValue() + "%");
case ENDS_WITH:
return (root, query, criteriaBuilder) ->
criteriaBuilder.like(root.get(input.getFieldName()), "%" + input.getValue());
case CONTAINS:
return (root, query, criteriaBuilder) ->
criteriaBuilder.like(root.get(input.getFieldName()), "%" + input.getValue() + "%");
default:
throw new RuntimeException("Operation not supported yet");
}
}
过滤器 DTO 如下所示:
@Data
public class TrafficDataFilterDTO {
private String fieldName;
private TrafficDataFilterOperator operator;
private String value;
}
奇怪的是,当我为两个不同的过滤器 object 调用此代码时,lambda 似乎只使用一个 input
值,而它 returns 我只是一个查询对于第一个标准。这一定是与 java lambda 参数相关的问题,但我不能确切地说出它是什么。
真实场景:
当我有两个不同的过滤器时 object:
{ "fieldName": "version", "operator": "EQUALS", "value": "EN_UK" }, { "fieldName": "isManaged", "operator": "EQUALS", "value": true }
方法 createSpecification(final TrafficDataFilterDTO input) 被调用两次,输入值正确(对于每个过滤器),但包含 lambda 的行
criteriaBuilder.equal(root.get(input.getFieldName()), input.getValue());
被第一个过滤器调用两次 object
等待解决方案和解释为什么会这样。
Specificiation.and()
returns 一个新的 Specification
因此您加入规范的代码不起作用。
您需要加入这样的规范:
Specification<TrafficData> specification = Specification.where(specificationList.remove(0));
return specificationList.stream().reduce(specification, Specification::and);