Home > Blockchain >  How can I use Java 8 Stream operators in order to obtain a BigDecimal value representing the sum of
How can I use Java 8 Stream operators in order to obtain a BigDecimal value representing the sum of

Time:02-25

I am experimenting with Java 8 streams, and I have the following problem. I have this WalletWrapperDTO class:

@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
public class WalletWrapperDTO {
    List<WalletDTO> walletsDTOList;
    BigDecimal totalAmount;
}

As you can see it only contains two fields:

  • A list of WalletDTO objects. The WalletDTO class contains a BigDecimal amount field representing a number of coins related to the specific wallet.
  • The totalAmount field. This fields will contains the sum of all the amount fields value of each objects of the previous list.

Then into a service method I have something like this:

@Override
@Transactional
public WalletWrapperDTO getAllWalletsOfAnUser(int userId) throws NotFoundException {
    WalletWrapperDTO result = new WalletWrapperDTO();
    
    List<Wallet> walletsList = this.walletRepository.findByUser_Id(userId);
    if(walletsList.isEmpty()) {
        throw new NotFoundException(String.format("The user having ID %s has no wallet", Integer.toString(userId)));
    }

    List<WalletDTO> walletsDTOList = Arrays.asList(conversionService.convert(walletsList, WalletDTO[].class));
    walletsDTOList.forEach( (e) -> e.setUser(null)  );
    
    List<BigDecimal> walletAmount = walletsDTOList.stream()
                                                  .map(WalletDTO::getAmount)
                                                  .collect(Collectors.toList());
    System.out.println("walletAmount: "   walletAmount);
    
    result.setWalletsDTOList(walletsDTOList);
    
    return result;
}

Basically this method first retrieve a list of Wallet from a repository, then it convert it into a list of WalletDTO objects.

Finally I wrote these lines of code:

List<BigDecimal> walletAmount = walletsDTOList.stream()
                                              .map(WalletDTO::getAmount)
                                              .collect(Collectors.toList());
System.out.println("walletAmount: "   walletAmount);

Basically I created a new walletAmount list containing the values of the amount field of each WalletDTO contained in the original walletsDTOList list. Then I print it. It works fine, and I obtained an output like this:

walletAmount: [0.6108105, 0, 0, 0, 0, 0]

What I really have to do now is that instead this list I need to obtain the sum of all the values into this derived list (that must be a BigDecimal value).

Starting from my previous code, what could be a good solution? It is not clear for me if I can use the sum() method or the reduce() method.

CodePudding user response:

You can use a map/reduce approach:

BigDecimal totalAmount = walletsDTOList.stream().map(WalletDTO::getAmount).reduce(BigDecimal.ZERO, BigDecimal::add);

The map() call will map the WalletDTO objects to BigDecimal objects and the reduce call will sum all of them.

CodePudding user response:

Ok, here is what I came up with to sum the values and then update the totalAmount field.

  • stream the WalletWrapperDTO list
  • then, for each wrapper Object, create a new one that contains.
    • the current walletDTOList
    • then sum of the wallets in that list
  • return the newly created object to a new list.
List<WalletWrapperDTO> wrappers = new ArrayList<>(); // populated somewhere

List<WalletWrapperDTO> updatedwrappers = wrappers.stream()
        .map(getWrap->new WalletWrapperDTO(
                getWrap.getWalletsDTOList(),                 
                getWrap.walletsDTOList.stream().map(WalletDTO::getAmount)
                    .reduce(BigDecimal.ZERO, BigDecimal::add)))
        .toList();

The updatedwrappers list should have individual WalletWrapperDTO objects that contain the original list of WalletDTO instances plus the totalAmount.

  • Related