如何总结具有特定 ID 的列表中对象的属性值,并使用 Streams 将其分配给另一个对象
How to Sum up the attribute values of objects in a list having particular IDs and assign it to another object using Streams
我的类.
class MyLoan {
private Long loanId;
private BigDecimal loanAmount;
private BigDecimal totalPaid;
....
}
class Customer {
private Long loanId;
private List<MyLoan> myLoan;
}
我想从 Customer
迭代 myLoan
并计算 totalPaid
数量。
我的逻辑是“如果 loanId
是 23491L
或 23492L
,则添加这两个 loanId
的 loanAmount
并设置值在 loanId
23490L
的 totalPaid
数量中。totalPaid
数量 总是显示为零 我的逻辑如下。
并且想使用Java8个流,但是使用流的时候无法写多个条件
BigDecimal spreadAmount;
for (MyLoan myloan: customer.getMyLoan()) {
if (myloan.getLoanId() == 23491L || myloan.getLoanId() == 23492L) {
spreadAmount = spreadAmount.add(myloan.getLoanAmount());
}
if (myloan.getLoanId() == 23490L) {
myloan.setTotalPaid(spreadAmount);
}
}
totalPaid
字段未被修改,因为您的 MyLoan
实例在其他两个 MyLoan
之前遇到了 ID 为 23490l 的实例。
正如@Silvio Mayolo 在评论中建议的那样,您应该首先使用临时变量计算总量,然后将其分配给 ID 为 23490l 的 MyLoan
实例的 totalPaid
字段。
这是您尝试执行的流式实现:
//If to make sure that the element MyLoan invoking the setter is actually present
if (myLoan.stream().map(MyLoan::getLoanId).anyMatch(value -> value == 23490l)){
myLoan.stream()
.filter(loan -> loan.getLoanId() == 23490l)
.findFirst()
.get()
.setTotalPaid(myLoan.stream()
.filter(loan -> loan.getLoanId() == 23491l || loan.getLoanId() == 23492l)
.map(MyLoan::getLoanAmount)
.reduce(BigDecimal.valueOf(0), (a, b) -> a = a.add(b)));
}
警告
在使用终端操作 findFirst()
检索到的 Optional
上调用的方法 get()
如果 ID 为 23490l 的 MyLoan
可能会抛出 NoSuchElementException
不在列表中。您应该首先确保该元素存在,就像我对 if 语句所做的那样。
第二个(不好的做法)可能涉及捕获 get()
抛出的 NoSuchElementException
,以防所需的 MyLoan
不存在。正如评论中指出的那样,捕获 RuntimeException
(NoSuchElementException
是它的子类)是一种不好的做法,因为我们应该调查问题的根源而不是简单地捕获异常.老实说,第二种方法是(懒惰的)最后的手段,只是为了展示另一种可能的处理方式。
首先,您需要获取要为其定义总支付金额的贷款。如果此步骤成功,则计算总数。
为了使用流找到具有特定 ID 的 loan,您需要在 customers loans 上创建流并申请filter()
连同findFirst()
就可以了。它将为您提供来自流的 第一个元素,该元素与传递到 过滤器 的谓词相匹配。因为流中可能不存在结果,所以 findFirst()
returns 一个 Optional
对象。
可选 class 提供了广泛的交互方法,如 orElse()
、ifPresent()
、orElse()
等。避免盲目使用 get()
,除非您没有检查值是否存在,在许多情况下这不是处理它的最方便的方法。就像下面的代码一样,ifPresent()
用于在存在值时继续执行逻辑。
因此,如果找到所需的贷款,下一步就是计算总额。这是通过过滤掉目标 ID,通过应用 map()
提取金额并使用 reduce()
作为终端操作将金额加在一起来完成的。
public static void setTotalPaid(Customer customer, Long idToSet, Long... idsToSumUp) {
List<MyLoan> loans = customer.getMyLoan();
getLoanById(loans, idToSet).ifPresent(loan -> loan.setTotalPaid(getTotalPaid(loans, idsToSumUp)));
}
public static Optional<MyLoan> getLoanById(List<MyLoan> loans, Long id) {
return loans.stream()
.filter(loan -> loan.getLoanId().equals(id))
.findFirst();
}
public static BigDecimal getTotalPaid(List<MyLoan> loans, Long... ids) {
Set<Long> targetLoans = Set.of(ids); // wrapping with set to improve performance
return loans.stream()
.filter(loan -> targetLoans.contains(loan.getLoanId()))
.map(MyLoan::getLoanAmount)
.reduce(BigDecimal.ZERO, BigDecimal::add);
}
我的类.
class MyLoan {
private Long loanId;
private BigDecimal loanAmount;
private BigDecimal totalPaid;
....
}
class Customer {
private Long loanId;
private List<MyLoan> myLoan;
}
我想从 Customer
迭代 myLoan
并计算 totalPaid
数量。
我的逻辑是“如果 loanId
是 23491L
或 23492L
,则添加这两个 loanId
的 loanAmount
并设置值在 loanId
23490L
的 totalPaid
数量中。totalPaid
数量 总是显示为零 我的逻辑如下。
并且想使用Java8个流,但是使用流的时候无法写多个条件
BigDecimal spreadAmount;
for (MyLoan myloan: customer.getMyLoan()) {
if (myloan.getLoanId() == 23491L || myloan.getLoanId() == 23492L) {
spreadAmount = spreadAmount.add(myloan.getLoanAmount());
}
if (myloan.getLoanId() == 23490L) {
myloan.setTotalPaid(spreadAmount);
}
}
totalPaid
字段未被修改,因为您的 MyLoan
实例在其他两个 MyLoan
之前遇到了 ID 为 23490l 的实例。
正如@Silvio Mayolo 在评论中建议的那样,您应该首先使用临时变量计算总量,然后将其分配给 ID 为 23490l 的 MyLoan
实例的 totalPaid
字段。
这是您尝试执行的流式实现:
//If to make sure that the element MyLoan invoking the setter is actually present
if (myLoan.stream().map(MyLoan::getLoanId).anyMatch(value -> value == 23490l)){
myLoan.stream()
.filter(loan -> loan.getLoanId() == 23490l)
.findFirst()
.get()
.setTotalPaid(myLoan.stream()
.filter(loan -> loan.getLoanId() == 23491l || loan.getLoanId() == 23492l)
.map(MyLoan::getLoanAmount)
.reduce(BigDecimal.valueOf(0), (a, b) -> a = a.add(b)));
}
警告
在使用终端操作 findFirst()
检索到的 Optional
上调用的方法 get()
如果 ID 为 23490l 的 MyLoan
可能会抛出 NoSuchElementException
不在列表中。您应该首先确保该元素存在,就像我对 if 语句所做的那样。
第二个(不好的做法)可能涉及捕获 get()
抛出的 NoSuchElementException
,以防所需的 MyLoan
不存在。正如评论中指出的那样,捕获 RuntimeException
(NoSuchElementException
是它的子类)是一种不好的做法,因为我们应该调查问题的根源而不是简单地捕获异常.老实说,第二种方法是(懒惰的)最后的手段,只是为了展示另一种可能的处理方式。
首先,您需要获取要为其定义总支付金额的贷款。如果此步骤成功,则计算总数。
为了使用流找到具有特定 ID 的 loan,您需要在 customers loans 上创建流并申请filter()
连同findFirst()
就可以了。它将为您提供来自流的 第一个元素,该元素与传递到 过滤器 的谓词相匹配。因为流中可能不存在结果,所以 findFirst()
returns 一个 Optional
对象。
可选 class 提供了广泛的交互方法,如 orElse()
、ifPresent()
、orElse()
等。避免盲目使用 get()
,除非您没有检查值是否存在,在许多情况下这不是处理它的最方便的方法。就像下面的代码一样,ifPresent()
用于在存在值时继续执行逻辑。
因此,如果找到所需的贷款,下一步就是计算总额。这是通过过滤掉目标 ID,通过应用 map()
提取金额并使用 reduce()
作为终端操作将金额加在一起来完成的。
public static void setTotalPaid(Customer customer, Long idToSet, Long... idsToSumUp) {
List<MyLoan> loans = customer.getMyLoan();
getLoanById(loans, idToSet).ifPresent(loan -> loan.setTotalPaid(getTotalPaid(loans, idsToSumUp)));
}
public static Optional<MyLoan> getLoanById(List<MyLoan> loans, Long id) {
return loans.stream()
.filter(loan -> loan.getLoanId().equals(id))
.findFirst();
}
public static BigDecimal getTotalPaid(List<MyLoan> loans, Long... ids) {
Set<Long> targetLoans = Set.of(ids); // wrapping with set to improve performance
return loans.stream()
.filter(loan -> targetLoans.contains(loan.getLoanId()))
.map(MyLoan::getLoanAmount)
.reduce(BigDecimal.ZERO, BigDecimal::add);
}