如何对 Java 中的对象进行分组 8

How to group objects in Java 8

WalletCreditNoteVO a1 = new WalletCreditNoteVO(1L, 1L, "A", WalletCreditNoteStatus.EXPIRED, null, null, CreditNoteType.CAMPAIGN_VOUCHER, BigDecimal.ONE, BigDecimal.ONE, "GBP");
WalletCreditNoteVO a2 = new WalletCreditNoteVO(1L, 1L, "A", WalletCreditNoteStatus.EXPIRED, null, null, CreditNoteType.CAMPAIGN_VOUCHER, BigDecimal.ONE, BigDecimal.TEN, "GBP");
WalletCreditNoteVO a3 = new WalletCreditNoteVO(2L, 1L, "A", WalletCreditNoteStatus.EXPIRED, null, null, CreditNoteType.CAMPAIGN_VOUCHER, BigDecimal.ONE, BigDecimal.ONE, "GBP");
WalletCreditNoteVO a4 = new WalletCreditNoteVO(2L, 1L, "A", WalletCreditNoteStatus.EXPIRED, null, null, CreditNoteType.CAMPAIGN_VOUCHER, BigDecimal.ONE, BigDecimal.TEN, "GBP");

final List<WalletCreditNoteVO> walletCreditNoteVOs = Lists.newArrayList(a1, a2, a3, a4);


Map<WalletCreditNoteVO, BigDecimal> collect2 = walletCreditNoteVOs.stream().collect(
        groupingBy(wr -> new WalletCreditNoteVO(wr.getCreditNoteId(), wr.getWalletCustomerId(), wr.getCreditNoteTitle(),
                        wr.getWalletCreditNoteStatus(), wr.getCreditNoteStartDate(), wr.getCreditNoteExpiryDate(), wr.getCreditNoteType(), wr.getCreditNoteValue(), wr.getCurrency()),
                mapping(WalletCreditNoteVO::getAvailableBalance,
                        reducing(BigDecimal.ZERO, (sum, elem) -> sum.add(elem)))));

我想根据 getWalletCreditNoteStatus

的状态引入最终归约的条件是 BigDecimal 列表中的总和(如上所述)或最后一个值

有人可以帮忙吗。


谢谢@xiumeteo。下面是改进的解决方案

Function<WalletCreditNoteVO, WalletCreditNoteVO> function = wr -> new WalletCreditNoteVO(wr.getCreditNoteId(), wr.getWalletCustomerId(), wr.getCreditNoteTitle(),
        wr.getWalletCreditNoteStatus(), wr.getCreditNoteStartDate(), wr.getCreditNoteExpiryDate(), wr.getCreditNoteType(), wr.getCreditNoteValue(), wr.getCurrency());

final Map<WalletCreditNoteVO, BigDecimal> collectMap =
        walletCreditNoteVOs.stream()
                .collect(groupingBy(function, LinkedHashMap::new, Collectors.collectingAndThen(
                        toList(),
                        (list) -> {
                            final List<BigDecimal> availableBalances = list.stream().map(WalletCreditNoteVO::getAvailableBalance).collect(toList());
                            if (list.stream().allMatch(WalletCreditNoteVO::isStatusExpired)) {
                                return availableBalances.stream().filter(o -> o != null).reduce((a, b) -> b).orElse(null).abs();
                            } else {
                                return availableBalances.stream().filter(o -> o != null).reduce(BigDecimal.ZERO, BigDecimal::add);
                            }
                        })));

List<WalletCreditNoteVO> walletCreditNoteVOGrouped = new ArrayList<>();
for(Map.Entry<WalletCreditNoteVO, BigDecimal> entry : collectMap.entrySet()){
    WalletCreditNoteVO key = entry.getKey();
    key.setAvailableBalance(entry.getValue());
    walletCreditNoteVOGrouped.add(key);
}

我现在想删除 'for loop',流逻辑应该只给我一个 WalletCreditNoteVO 列表,而不是 WalletCreditNoteVO 的 Map 作为键和 BigDecimal 作为值,值直接在 WalletCreditNoteVO 中设置

再次感谢大家(我无法在我的评论中添加代码,所以在此处添加)。

所以我对你的案例进行了测试,我创建了一个与你的相似的虚拟 class:

public static class Something{
        private String name;
        private Integer sum;
        private boolean  checker;

        public Something(String name, Integer sum, boolean checker) {
            this.name = name;
            this.sum = sum;
            this.checker = checker;
        }

        public String getName() {
            return name;
        }

        public boolean isChecker() {
            return checker;
        }

        public Integer getSum() {
            return sum;
        }

        @Override
        public boolean equals(Object o) {
            if (this == o) {
                return true;
            }

            if (o == null || getClass() != o.getClass()) {
                return false;
            }

            Something something = (Something) o;

            return new EqualsBuilder().append(getName(), something.getName()).append(getSum(), something.getSum()).isEquals();
        }

        @Override
        public int hashCode() {
            return new HashCodeBuilder(17, 37).append(getName()).append(getSum()).toHashCode();
        }
    }

然后我做了这个小测试

List<Something> items = Arrays.asList(new Something("name", 10, false), new Something("name", 14, true), new Something("name", 11, false),
           new Something("name", 11, false), new Something("noName", 12, false));

final Map<Something, Integer> somethingToSumOrLastElement =
  items.stream()
    .collect(Collectors.groupingBy(Function.identity(), 
            Collectors.collectingAndThen(
                Collectors.toList(), // first we collect all your related items into a list
                (list) -> { //this collector allow us to have a finisher, Function<List<Something>, Object>, let's define it
                    final List<Integer> integerStream = list.stream().map(Something::getSum).collect(Collectors.toList());
                    if (list.stream().allMatch(Something::isChecker)) { // we check for the method you want to check
                      //you have to change this depending on required logic
                      //for this case if that's true for every element in the list, we do the reduce by summing
                       return integerStream.stream().reduce(0, (sum, next) -> sum + next);
                    }
                    //if not, we just get the last element of that list
                    return integerStream.stream().reduce(0, (sum, next) -> next);
      })));

我认为这没问题,但也许有人对如何处理您的问题有更好的想法。 如果您需要澄清,请联系我 :)