java - 使用 Streams 将 BigDecimals 相加

标签 java bigdecimal java-8 java-stream

我有一组 BigDecimal(在本例中为 LinkedList),我想将它们加在一起。是否可以为此使用流?

我注意到 Stream 类有几个方法

Stream::mapToInt
Stream::mapToDouble
Stream::mapToLong

每个都有一个方便的 sum() 方法。但是,正如我们所知,floatdouble 算术几乎总是一个坏主意。

那么,有没有一种方便的方法来总结 BigDecimals?

这是我目前的代码。

public static void main(String[] args) {
    LinkedList<BigDecimal> values = new LinkedList<>();
    values.add(BigDecimal.valueOf(.1));
    values.add(BigDecimal.valueOf(1.1));
    values.add(BigDecimal.valueOf(2.1));
    values.add(BigDecimal.valueOf(.1));

    // Classical Java approach
    BigDecimal sum = BigDecimal.ZERO;
    for(BigDecimal value : values) {
        System.out.println(value);
        sum = sum.add(value);
    }
    System.out.println("Sum = " + sum);

    // Java 8 approach
    values.forEach((value) -> System.out.println(value));
    System.out.println("Sum = " + values.stream().mapToDouble(BigDecimal::doubleValue).sum());
    System.out.println(values.stream().mapToDouble(BigDecimal::doubleValue).summaryStatistics().toString());
}

如您所见,我正在使用 BigDecimal::doubleValue() 总结 BigDecimal,但这(如预期的那样)并不精确。

后人回答编辑:

这两个答案都非常有帮助。我想补充一点:我的真实场景不涉及原始 BigDecimal 的集合,它们包含在发票中。但是,我可以通过使用 map() 函数来修改 Aman Agnihotri 的答案来解决这个问题:

public static void main(String[] args) {

    LinkedList<Invoice> invoices = new LinkedList<>();
    invoices.add(new Invoice("C1", "I-001", BigDecimal.valueOf(.1), BigDecimal.valueOf(10)));
    invoices.add(new Invoice("C2", "I-002", BigDecimal.valueOf(.7), BigDecimal.valueOf(13)));
    invoices.add(new Invoice("C3", "I-003", BigDecimal.valueOf(2.3), BigDecimal.valueOf(8)));
    invoices.add(new Invoice("C4", "I-004", BigDecimal.valueOf(1.2), BigDecimal.valueOf(7)));

    // Classical Java approach
    BigDecimal sum = BigDecimal.ZERO;
    for(Invoice invoice : invoices) {
        BigDecimal total = invoice.unit_price.multiply(invoice.quantity);
        System.out.println(total);
        sum = sum.add(total);
    }
    System.out.println("Sum = " + sum);

    // Java 8 approach
    invoices.forEach((invoice) -> System.out.println(invoice.total()));
    System.out.println("Sum = " + invoices.stream().map((x) -> x.total()).reduce((x, y) -> x.add(y)).get());
}

static class Invoice {
    String company;
    String invoice_number;
    BigDecimal unit_price;
    BigDecimal quantity;

    public Invoice() {
        unit_price = BigDecimal.ZERO;
        quantity = BigDecimal.ZERO;
    }

    public Invoice(String company, String invoice_number, BigDecimal unit_price, BigDecimal quantity) {
        this.company = company;
        this.invoice_number = invoice_number;
        this.unit_price = unit_price;
        this.quantity = quantity;
    }

    public BigDecimal total() {
        return unit_price.multiply(quantity);
    }

    public void setUnit_price(BigDecimal unit_price) {
        this.unit_price = unit_price;
    }

    public void setQuantity(BigDecimal quantity) {
        this.quantity = quantity;
    }

    public void setInvoice_number(String invoice_number) {
        this.invoice_number = invoice_number;
    }

    public void setCompany(String company) {
        this.company = company;
    }

    public BigDecimal getUnit_price() {
        return unit_price;
    }

    public BigDecimal getQuantity() {
        return quantity;
    }

    public String getInvoice_number() {
        return invoice_number;
    }

    public String getCompany() {
        return company;
    }
}

最佳答案

原答案

是的,这是可能的:

List<BigDecimal> bdList = new ArrayList<>();
//populate list
BigDecimal result = bdList.stream()
        .reduce(BigDecimal.ZERO, BigDecimal::add);

它的作用是:

  1. 获取List<BigDecimal> .
  2. 把它变成 Stream<BigDecimal>
  3. 调用reduce方法。

    3.1。我们提供一个身份值进行加法,即 BigDecimal.ZERO .

    3.2。我们指定 BinaryOperator<BigDecimal> ,这增加了两个 BigDecimal的,通过方法引用 BigDecimal::add .

编辑后更新答案

我看到您添加了新数据,因此新答案将变为:

List<Invoice> invoiceList = new ArrayList<>();
//populate
Function<Invoice, BigDecimal> totalMapper = invoice -> invoice.getUnit_price().multiply(invoice.getQuantity());
BigDecimal result = invoiceList.stream()
        .map(totalMapper)
        .reduce(BigDecimal.ZERO, BigDecimal::add);

除了我添加了totalMapper 之外,几乎相同。变量,其函数来自 InvoiceBigDecimal并返回该发票的总价。

然后我得到一个 Stream<Invoice> ,将其映射到 Stream<BigDecimal>然后将其缩减为 BigDecimal .

现在,从 OOP 设计的角度来看,我建议您也实际使用 total()方法,你已经定义了,那么它就变得更容易了:

List<Invoice> invoiceList = new ArrayList<>();
//populate
BigDecimal result = invoiceList.stream()
        .map(Invoice::total)
        .reduce(BigDecimal.ZERO, BigDecimal::add);

这里我们直接使用map中的方法引用方法。

关于java - 使用 Streams 将 BigDecimals 相加,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22635945/

相关文章:

java - 在以下代码中使用 map 时出错

java - 如何解决JavaFX中Scene Builder不响应的问题?

java - 如何开始编写代码覆盖工具?

java - 在gradle中的jar命令中使用include和exclude并没有包含所有需要的类

java - 使用 JaxB 解码具有唯一值

java - JTable 单元格编辑器仅接受数字

java - 如何对 BigDecimal 对象列表进行排序

java - Maven jaxws 插件 - 跳过执行

java - 为什么我的 BigDecimal 0.0000 不等于 BigDecimal.ZERO?

Java 8 将 HashSet 转换为 HashMap