使用比较器删除值进行流

时间:2018-11-18 21:06:00

标签: java null stream equals comparator

我是一名初级开发人员,对Java流的使用经验很少。我已经确定(通过一些额外的日志记录),下面的流正在删除一条我正在寻找的记录,但我不知道为什么。请注意,我没有编写此代码,而这样做的人已离开公司。该项目正在使用Spring。

ConfirmCode表的结构如下:

  Name              Type    Length  Not Null
  confirm_code_id   int     11      True
  account_id        varchar 20      False
  product_id        varchar 20      False
  dimension         varchar 55      False
  confirm_code      int     1       False
  confirm_desc      varchar 50      False
  action_enum       enum    0       False 
  sms_keywords      varchar 255     False 

此表包含特定的枚举,根据设计,account_id,product_id和维度允许为空:

  ConfirmCode
  accountId productId dimension code desc               enum     keywords
                                  2  Need to Reschedule RESCHED  {not important}
                                  7  Call Transferred   TRANSFER {not important}
                                 -1  Help               HELP     {not important}
                                 -2  Opt In             OPT IN   {not important}
                                 -3  Opt Out            OPT OUT  {not important}
                                 -4  Response           RESPONSE {not important}    
                                  1  Confirmed          CONFIRM  {not important}

但是,默认情况下,客户(accountID)可以覆盖绑定到枚举的代码。例如:

  ConfirmCode
  accountId productId dimension             code desc               enum     keywords
  704442    RemindMe  Appointment Reminder  2    Confirmed          CONFIRM  {not important}    

由于accountId,productId和Dimension允许为空,因此Spring运行的查询需要考虑到这一点,并且客户需要覆盖默认值,如您在上面看到的那样(在这种情况下,父帐户为null)。 / p>

Query:
public interface ConfirmCodeRepository extends JpaRepository<ConfirmCode, Long> {

  @Query("SELECT c FROM ConfirmCode c WHERE (accountId is null OR accountId = :parentAccountId OR accountId = :accountId) "
        + " AND (productId = :productId OR productId is NULL)"
        + " AND (dimension is null OR dimension = :dimension)")

  public List<ConfirmCode> findByAccountIdAndProductIdAndDimension(
        @Param("accountId") String accountId, @Param("parentAccountId") String parentAccountId,
        @Param("productId") String productId, @Param("dimension") String dimension);

我遇到的问题是,当为客户704442查询ConfirmCode表时,将为该客户返回该记录,但是在经过流中的Comparator代码之后,该记录将被删除。仅accountId,productId和Dimension为空的记录。这是对查询结果集进行逻辑处理的代码:

@Repository
public class ConfirmCodeDAO {

    @Autowired
    ConfirmCodeRepository confirmCodeRepo;
    private static final Logger logger = LoggerFactory.getLogger(PreferenceService.class);

    public Set<ConfirmCode> findByAccountIdAndParentAccountIdAndProductIdAndDimension(
            String accountId,
            String parentAccountId, String productId, String dimension) {

        List<ConfirmCode> list = confirmCodeRepo
                .findByAccountIdAndProductIdAndDimension(accountId, parentAccountId, productId,
                        dimension);
        list.forEach(r -> logger.info("list: " + r.toString()));

        Set<ConfirmCode> set = confirmCodeRepo
                .findByAccountIdAndProductIdAndDimension(accountId, parentAccountId, productId,
                        dimension)
                .stream()
                .sorted(Comparator.comparing(ConfirmCode::getActionEnum,
                        Comparator.nullsFirst(Comparator.naturalOrder())))
                .sorted(Comparator.comparing(ConfirmCode::getDimension,
                        Comparator.nullsFirst(Comparator.naturalOrder())))
                .sorted(Comparator.comparing(ConfirmCode::getProductId,
                        Comparator.nullsFirst(Comparator.naturalOrder())))
                .sorted(Comparator.comparing(ConfirmCode::getAccountId,
                        Comparator.nullsFirst(Comparator.reverseOrder())))
                .collect(Collectors.toMap(ConfirmCode::getConfirmCode, confirmCode -> confirmCode,
                        (c1, c2) -> c2))
                .entrySet()
                .stream()
                .map(e -> e.getValue())
                .collect(Collectors.toSet());
        set.forEach(r -> logger.info("set2: " + r.toString()));
        return set;
    }
}

以下是“列表”对象的日志记录:

Calling confirmCodeDAO with: 704442, parentAccountId: null, productId: RemindMe, dimension: Appointment Reminder
list: [accountId=704442, productId=RemindMe, dimension=Appointment Reminder, confirmCode=2, confirmDesc=Confirmed, actionEnum=CONFIRM, smsKeywords={not important}]
list: [accountId=null, productId=null, dimension=null, confirmCode=1, confirmDesc=Confirmed, actionEnum=CONFIRM, smsKeywords={not important}]
list: [accountId=null, productId=null, dimension=null, confirmCode=2, confirmDesc=Need to Reschedule, actionEnum=RESCHED, smsKeywords={not important}]
list: [accountId=null, productId=null, dimension=null, confirmCode=7, confirmDesc=Call Transferred, actionEnum=TRANSFER, smsKeywords={not important}, account=null, responseType=null]
list: [accountId=null, productId=null, dimension=null, confirmCode=3, confirmDesc=Repeat, actionEnum=REPEAT, smsKeywords={not important}, account=null, responseType=null]
list: [accountId=null, productId=null, dimension=null, confirmCode=-1, confirmDesc=Help, actionEnum=HELP, smsKeywords={not important}, account=null, responseType=null]
list: [accountId=null, productId=null, dimension=null, confirmCode=-2, confirmDesc=Opt In, actionEnum=OPT IN, smsKeywords={not important}, account=null, responseType=null]
list: [accountId=null, productId=null, dimension=null, confirmCode=-3, confirmDesc=Opt Out, actionEnum=OPT OUT, smsKeywords={not important}, account=null, responseType=null]
list: [accountId=null, productId=null, dimension=null, confirmCode=-4, confirmDesc=Response, actionEnum=RESPONSE, smsKeywords={not important}, account=null, responseType=null]
list: [accountId=null, productId=null, dimension=null, confirmCode=-5, confirmDesc=Cancelled, actionEnum=CANCEL, smsKeywords={not important}, account=null, responseType=null]

以下是“设置”对象的日志记录:

set: [accountId=null, productId=null, dimension=null, confirmCode=-1, confirmDesc=Help, actionEnum=HELP, smsKeywords={not important}]
set: [accountId=null, productId=null, dimension=null, confirmCode=1, confirmDesc=Confirmed, actionEnum=CONFIRM, smsKeywords={not important}]
set: [accountId=null, productId=null, dimension=null, confirmCode=-5, confirmDesc=Cancelled, actionEnum=CANCEL, smsKeywords={not important}]
set: [accountId=null, productId=null, dimension=null, confirmCode=7, confirmDesc=Call Transferred, actionEnum=TRANSFER, smsKeywords={not important}]
set: [accountId=null, productId=null, dimension=null, confirmCode=3, confirmDesc=Repeat, actionEnum=REPEAT, smsKeywords={not important}, account=null, responseType=null]
set: [accountId=null, productId=null, dimension=null, confirmCode=-2, confirmDesc=Opt In, actionEnum=OPT IN, smsKeywords={not important}, account=null, responseType=null]
set: [accountId=null, productId=null, dimension=null, confirmCode=-4, confirmDesc=Response, actionEnum=RESPONSE, smsKeywords={not important}, account=null, responseType=null]
set: [accountId=null, productId=null, dimension=null, confirmCode=-3, confirmDesc=Opt Out, actionEnum=OPT OUT, smsKeywords={not important}, account=null, responseType=null]

您可以看到在查看流代码之后,我需要的记录被删除了。请为此提供建议,并感谢您的宝贵时间!

1 个答案:

答案 0 :(得分:0)

排序的本身不能删除元素。但是通过使用

收集列表
toMap.collect(Collectors.toMap(ConfirmCode::getConfirmCode, confirmCode -> 
confirmCode, (c1, c2) -> c2))

每个属性的confirmCode只保留一个。

此toMap收集器的工作方式如下:

第一个参数定义了键,因此它将对象ConfigmCode的属性ConfirmCode作为键(名称有点误导)。第二个是值confirmCode -> confirmCode,因此整个对象都保留为值。因此,我们得到一个Map<Integer, ConfirmCode>

第三参数描述了如果地图中存在关键区域,那么如何合并两个值。函数(c1,c2) -> c2简单地说:采用第二个。

在您的列表中,第一个和第三个元素都具有confirmCode = 2,因此,仅第二个元素保留在地图中。

正如评论中所讨论的那样,由于比较器首先将null排序,因此这仅会丢弃第二个元素(在输入列表中),其confirmItem = 2。

现在,映射包含预期的元素,但是当将值收集到一组中时,ConfirmCode的equals方法将定义为相等的对象(如果它们具有相同的actionEnum)。虽然第一个元素(排序到末尾)具有与列表中第二个元素相同的actionEnum,但收集器仅保留第一个元素。