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. TheWalletDTO
class contains aBigDecimal amount
field representing a number of coins related to the specific wallet. - The
totalAmount
field. This fields will contains the sum of all theamount
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
- the current
- 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
.