ryv*_*age 158 java bigdecimal java-8 java-stream
我有一个BigDecimals的集合(在这个例子中,a LinkedList)我想加在一起.是否可以使用流?
我注意到这个Stream课有几种方法
Stream::mapToInt
Stream::mapToDouble
Stream::mapToLong
Run Code Online (Sandbox Code Playgroud)
每个都有一个方便的sum()方法.但是,我们知道,float和double算术几乎总是一个坏主意.
那么,有没有一种方便的方法来总结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());
}
Run Code Online (Sandbox Code Playgroud)
正如你所看到的,我正在总结BigDecimals BigDecimal::doubleValue(),但这(正如预期的那样)并不准确.
后代的回答后编辑:
这两个答案都非常有帮助.我想补充一点:我的现实场景不涉及原始集合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;
}
}
Run Code Online (Sandbox Code Playgroud)
ski*_*iwi 313
是的,这是可能的:
List<BigDecimal> bdList = new ArrayList<>();
//populate list
BigDecimal result = bdList.stream()
.reduce(BigDecimal.ZERO, BigDecimal::add);
Run Code Online (Sandbox Code Playgroud)
它的作用是:
List<BigDecimal>.Stream<BigDecimal>调用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);
Run Code Online (Sandbox Code Playgroud)
它基本上是一样的,除了我添加了一个totalMapper变量,从有一个函数Invoice来BigDecimal,并返回该发票的总价格.
然后我获得a Stream<Invoice>,将其映射到a Stream<BigDecimal>然后将其缩小为a BigDecimal.
现在,从OOP设计的角度来看,我建议您实际使用total()已经定义的方法,然后它变得更容易:
List<Invoice> invoiceList = new ArrayList<>();
//populate
BigDecimal result = invoiceList.stream()
.map(Invoice::total)
.reduce(BigDecimal.ZERO, BigDecimal::add);
Run Code Online (Sandbox Code Playgroud)
这里我们直接使用方法中的map方法引用.
该帖子已经有一个已检查的答案,但是该答案不会过滤空值。正确答案应通过使用Object :: nonNull函数作为谓词来防止出现空值。
BigDecimal result = invoiceList.stream()
.map(Invoice::total)
.filter(Objects::nonNull)
.filter(i -> (i.getUnit_price() != null) && (i.getQuantity != null))
.reduce(BigDecimal.ZERO, BigDecimal::add);
Run Code Online (Sandbox Code Playgroud)
这可以防止在我们减少时尝试对空值求和。
使用此方法汇总BigDecimal列表:
List<BigDecimal> values = ... // List of BigDecimal objects
BigDecimal sum = values.stream().reduce((x, y) -> x.add(y)).get();
Run Code Online (Sandbox Code Playgroud)
此方法仅将每个BigDecimal映射为BigDecimal,并通过对它们求和来减少它们,然后使用该get()方法返回它们.
这是另一种简单的方法来进行相同的求和:
List<BigDecimal> values = ... // List of BigDecimal objects
BigDecimal sum = values.stream().reduce(BigDecimal::add).get();
Run Code Online (Sandbox Code Playgroud)
更新
如果我在编辑的问题中编写类和lambda表达式,我会写如下:
import java.math.BigDecimal;
import java.util.LinkedList;
public class Demo
{
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)));
// Java 8 approach, using Method Reference for mapping purposes.
invoices.stream().map(Invoice::total).forEach(System.out::println);
System.out.println("Sum = " + invoices.stream().map(Invoice::total).reduce((x, y) -> x.add(y)).get());
}
// This is just my style of writing classes. Yours can differ.
static class Invoice
{
private String company;
private String number;
private BigDecimal unitPrice;
private BigDecimal quantity;
public Invoice()
{
unitPrice = quantity = BigDecimal.ZERO;
}
public Invoice(String company, String number, BigDecimal unitPrice, BigDecimal quantity)
{
setCompany(company);
setNumber(number);
setUnitPrice(unitPrice);
setQuantity(quantity);
}
public BigDecimal total()
{
return unitPrice.multiply(quantity);
}
public String getCompany()
{
return company;
}
public void setCompany(String company)
{
this.company = company;
}
public String getNumber()
{
return number;
}
public void setNumber(String number)
{
this.number = number;
}
public BigDecimal getUnitPrice()
{
return unitPrice;
}
public void setUnitPrice(BigDecimal unitPrice)
{
this.unitPrice = unitPrice;
}
public BigDecimal getQuantity()
{
return quantity;
}
public void setQuantity(BigDecimal quantity)
{
this.quantity = quantity;
}
}
}
Run Code Online (Sandbox Code Playgroud)
你可以总结出的值,BigDecimal使用流可重复使用的 收集器命名为summingUp:
BigDecimal sum = bigDecimalStream.collect(summingUp());
Run Code Online (Sandbox Code Playgroud)
该Collector可以实现这样的:
public static Collector<BigDecimal, ?, BigDecimal> summingUp() {
return Collectors.reducing(BigDecimal.ZERO, BigDecimal::add);
}
Run Code Online (Sandbox Code Playgroud)
如果你不介意第三方的依赖,有一个名为类Collectors2在Eclipse中集合其中包含的方法返回收藏家的总结和概括BigDecimal和BigInteger的。这些方法将函数作为参数,因此您可以从对象中提取 BigDecimal 或 BigInteger 值。
List<BigDecimal> list = mList(
BigDecimal.valueOf(0.1),
BigDecimal.valueOf(1.1),
BigDecimal.valueOf(2.1),
BigDecimal.valueOf(0.1));
BigDecimal sum =
list.stream().collect(Collectors2.summingBigDecimal(e -> e));
Assert.assertEquals(BigDecimal.valueOf(3.4), sum);
BigDecimalSummaryStatistics statistics =
list.stream().collect(Collectors2.summarizingBigDecimal(e -> e));
Assert.assertEquals(BigDecimal.valueOf(3.4), statistics.getSum());
Assert.assertEquals(BigDecimal.valueOf(0.1), statistics.getMin());
Assert.assertEquals(BigDecimal.valueOf(2.1), statistics.getMax());
Assert.assertEquals(BigDecimal.valueOf(0.85), statistics.getAverage());
Run Code Online (Sandbox Code Playgroud)
注意:我是 Eclipse Collections 的提交者。
| 归档时间: |
|
| 查看次数: |
107058 次 |
| 最近记录: |