我是一名初级开发人员,几乎没有使用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和维度按设计允许为null:
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被允许为null,因此Spring运行的查询需要考虑到这一点,以及客户覆盖默认值,正如您在上面看到的那样(在这种情况下,父帐户为null(。
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和维度为null的记录。以下是对查询的结果集执行逻辑的代码:
@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"对象的日志:
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]
你可以看到,在通过流代码后,我需要的记录被删除了。请对此提出建议,并感谢您抽出时间!
排序后的本身不能删除元素。但是通过使用收集列表
toMap.collect(Collectors.toMap(ConfirmCode::getConfirmCode, confirmCode ->
confirmCode, (c1, c2) -> c2))
每个属性confirmCode只保留一个。
这个toMap收集器的工作原理如下:
第一个参数定义键,因此它将对象ConfigmCode的属性confirmCode作为键(名称有点误导(。第二个是值confirmCode -> confirmCode
,所以整个对象都保持为值。因此我们得到了一个CCD_ 2。
第三个参数描述了如果映射中存在键区域,如何合并两个值。函数(c1,c2) -> c2
简单地说:取第二个。
在您的列表中,第一个和第三个元素都具有confirmCode=2,因此只有第二个元素保留在映射中。
正如评论中所讨论的,这只会删除confirmItem=2的第二个元素(在输入列表中(,因为比较器首先对null进行排序。
映射现在包含预期的元素,但当值被收集到一个集合时,ConfirmCode的equals方法将对象定义为相等(如果它们具有相同的actionEnum(。虽然第一个元素(排序到最后(与列表中的第二个元素具有相同的actionEnum,但收集器只保留第一个元素。