当前位置: 首页 > 知识库问答 >
问题:

使用流对BigDecimals进行加法

赫连实
2023-03-14

我有一个BigDecimals(在本例中是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的集合,它们包装在发票中。但是,我能够修改Aman Agnihotri的答案,通过使用map()函数来解释这个问题:

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;
    }
}

共有1个答案

邵正雅
2023-03-14

是的,这是可能的:

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

它所做的是:

>

  • 获取列表
  • 将其转换为
  • 调用reduce方法。

    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的函数,并返回该发票的总价。

    然后获取,将其映射到,然后将其还原为bigdecimal

    现在,从OOP设计的角度出发,我建议您也实际使用您已经定义的total()方法,这样它甚至会变得更容易:

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

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

  •  类似资料:
    • 我有一个对象列表。它们都有一个。我想对它们进行分组,并将字段加起来。 对于本例:

    • 我使用Django 3.08和PostgreSQL 12远程服务器。我已经搜索了Postgres和Django的文档,但是找不到关于Django如何/是否加密我的应用程序和数据库之间的流量的讨论。 在我看来,根据PostgreSQL中的设置,PostgreSQL中默认情况下使用md5加密对流量进行加密,并通过端口5432通过tcp发送流量。我的理解是,md5不再足以加密。然而,PostgreSQL

    • 我有一个这样的方法: 此方法需要以如下字符串形式返回3个最昂贵项目的产品ID:“item1,item2,item3”。我应该只能使用溪流,我被困在这里了。我应该能够按值对项目进行排序,然后获得产品ID,但我似乎无法使其正常工作。 编辑: 产品ID位于入口类中

    • 我正在使用反射来调用java.util.Stream.Stream上的方法,但由于实际实现(ReferencePipeline等)具有运行的实际代码,因此在调用时会收到非法的反射访问警告,如果没有该调用,它将无法工作。我想知道是否有一种方法可以自动将其委托给一个访问不非法的超级方法?也就是说,我想调用,其中是合法的,而不是或任何实现。 编辑这里是一些代码。是通过反射获得的流的具体实例。

    • 我有一系列的双值,我想求和,得到最大值。听起来非常适合这样做。方法有一个API注释,提醒我在我的一门计算机科学课程中学到了什么:如果按绝对值排序,求和问题的稳定性往往会更好。但是,不允许我指定要使用的比较器,它只会使用