【问题标题】:Java lambda keeps outer param value of first call even on second call [closed]Java lambda即使在第二次调用时也会保留第一次调用的外部参数值[关闭]
【发布时间】:2022-01-06 11:13:57
【问题描述】:

标题可能不太具有描述性,但我会尝试继续我的问题。

所以,我正在尝试使用 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;
}

奇怪的是,当我为两个不同的过滤器对象调用这段代码时,似乎 lambdas 只使用了一个 input 值,它只为第一个条件返回了一个查询。这可能是与 java lambda 参数有关的问题,但我无法确切地说出它是什么。

所以一个真实的场景:

当我有两个不同的过滤器对象时: { "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()); 被第一个过滤器对象调用两次

等待解决方案和解释为什么会发生这种情况。

【问题讨论】:

  • "似乎 lambdas 只使用一个输入值,它只针对第一个条件返回一个查询" 为什么会这样?这似乎是一个 XY 问题。您是在告诉我们您认为原因是什么,而不是告诉我们根本的问题。什么不起作用?
  • 注释不是代码的好地方。如果您认为可以澄清您的问题,请编辑问题。
  • 当我有两个不同的过滤器对象时:``` { "fieldName": "version", "operator": "EQUALS", "value": "EN_UK" }, { "fieldName": "isManaged", "operator": "EQUALS", "value": true } ``` 方法 createSpecification(final TrafficDataFilterDTO input) 被调用两次,使用正确的 input 值(对于每个过滤器),但包含 lambda @ 的行987654328@ 使用第一个过滤器值调用两次
  • 恕我直言,问题出在specificationList.forEach(specification::and); - Specificiation.and() 返回一个新的Specificiation 但你忽略了它,最后只返回第一个创建的specification

标签: java lambda criteria-api


【解决方案1】:

Specificiation.and() 返回一个新的Specification,因此您加入规范的代码不起作用。

你需要加入这样的规范:

    Specification<TrafficData> specification = Specification.where(specificationList.remove(0));

    return specificationList.stream().reduce(specification, Specification::and);

【讨论】:

  • 天啊,这当然是问题所在。我想我需要休息一下。谢谢
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-03-27
  • 1970-01-01
  • 1970-01-01
  • 2011-10-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多