【问题标题】:how to get sum and lowest date from the List<> with lambda如何使用 lambda 从 List<> 中获取总和和最低日期
【发布时间】:2018-11-03 21:00:11
【问题描述】:
public class BusinessLog {

private Date logDate;
private double prize;

}

给定对象BusinessLog,我需要对List&lt;BusinessLog&gt; list中的所有奖品进行总和,还需要返回列表中的最低日期,是否可以使用lambda,

我肯定可以用 forEach 做到这一点,但是如何用 lambda 做到这一点,

到目前为止,我尝试做的是,

    BigDecimal balance = BigDecimal.ZERO;

    if (list != null) {
        list.forEach(businessLog -> {
            balance.add(BigDecimal.valueOf(businessLog.getPrize()));
            // how to get lowest date 

        });
    }

【问题讨论】:

    标签: java lambda


    【解决方案1】:

    使用流媒体的解决方案

    要查找最短日期,您可以执行以下操作:

    Optional<Date> minDate = list.stream().map(v -> v.logDate).min(Date::compareTo);
    

    并计算总和:

    double sum = list.stream().mapToDouble(v -> v.prize).sum();
    

    我不会担心“优化”它并尝试在一个循环中完成它,除非这可证明是您系统的主要瓶颈(不太可能)。将这两个想法分开会使代码更易于理解和维护。

    您对 BigDecimal 的使用

    您将balance.add(...) 转换为BigDecimal 的代码实际上不会按照您编写的方式运行,因为BigDecimal 上的add 方法返回一个新实例,而不是改变现有实例。 BigDecimal 实例是不可变的。您不能为 balance 分配新值,因为它实际上是 lambda 上下文中的 final

    不过,使用BigDecimal 的想法是个好主意。您应该避免将double 用于任何需要精确小数位的内容(例如金钱)。如果将 prize 更改为 BigDecimal,则不能使用 sum(),但可以使用 reduce() 来实现相同的功能。

    BigDecimal sum = list.stream().map(v -> v.prize).reduce(BigDecimal.ZERO, BigDecimal::add);
    

    【讨论】:

    • 很好解释,关于 BigDecimal 谢谢,我错过了。
    【解决方案2】:

    要计算多个自定义聚合,您应该编写自定义 reducer。

    例如,以下 reducer 计算一个 BusinessLog 对象中的统计信息。下面假设要声明一个构造函数public BusinessLog(double prize, Date logDate)

    BusinessLog stats = 
            bl.stream()
            .reduce((log1, log2) -> new BusinessLog(
                    log1.getPrize() + log2.getPrize(),
                    log1.getLogDate().before(log2.getLogDate()) ?
                         log1.getLogDate() : log2.getLogDate()
                )).get();
    
    Date lowestDate = stats.getLogDate();
    double prizeSum = stats.getPrize();
    

    请注意,使用BusinessLog 作为临时统计数据持有者本质上是一种黑客行为。为此,您需要设计一个单独的类。

    【讨论】:

    • 但同时我也需要最低日期,所以我是否要再次为日期编写 lambda 表达式?
    • @tyro 你可以为此构建一个自定义收集器,但你也可以流两次
    • @tyro 添加了一个示例,该示例使用 reducer 在一个流遍历中计算两个聚合
    • @ErnestKiwele 无法解释为什么这里的反对票...从我这里获得 +1。顺便说一句,你不能轻易地为此创建一个专用类,你将如何为Date 指定一个身份?
    • @Ernest Kiwele 感谢您的回复,但喜欢将它们分开循环的想法
    猜你喜欢
    • 2021-03-31
    • 2015-04-28
    • 1970-01-01
    • 1970-01-01
    • 2016-12-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多