Saya memiliki koleksi BigDecimals (dalam contoh ini, a LinkedList
) yang ingin saya tambahkan bersama. Apakah mungkin menggunakan stream untuk ini?
Saya perhatikan Stream
kelas memiliki beberapa metode
Stream::mapToInt
Stream::mapToDouble
Stream::mapToLong
Masing-masing memiliki sum()
metode yang mudah . Tapi, seperti yang kita tahu, float
dan double
berhitung hampir selalu merupakan ide yang buruk.
Jadi, apakah ada cara mudah untuk menyimpulkan BigDecimals?
Ini adalah kode yang saya miliki sejauh ini.
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());
}
Seperti yang Anda lihat, saya menyimpulkan BigDecimal menggunakan BigDecimal::doubleValue()
, tapi ini (seperti yang diharapkan) tidak tepat.
Sunting pasca jawaban untuk keturunan:
Kedua jawaban itu sangat membantu. Saya ingin menambahkan sedikit: skenario kehidupan nyata saya tidak melibatkan koleksi mentah BigDecimal
, mereka dibungkus dalam faktur. Tapi, saya bisa mengubah jawaban Aman Agnihotri untuk akun ini dengan menggunakan map()
fungsi stream:
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;
}
}
sumber
Invoice::total
vsinvoice -> invoice.total()
.Collectors.summingInt()
, tetapi melewatkannya selamaBigDecimal
s. Daripada menulisreduce(blah blah blah)
yang sulit dibaca, akan lebih baik untuk menulis kolektor yang hilang untukBigDecimal
dan miliki.collect(summingBigDecimal())
di akhir saluran Anda.Posting ini sudah memiliki jawaban yang dicentang, tetapi jawabannya tidak memfilter untuk nilai nol. Jawaban yang benar harus mencegah nilai nol dengan menggunakan fungsi Object :: nonNull sebagai predikat.
Ini mencegah nilai nol dari upaya untuk dijumlahkan seperti yang kita kurangi.
sumber
Anda dapat meringkas nilai-nilai
BigDecimal
aliran menggunakan Kolektor yang dapat digunakan kembali bernama :summingUp
The
Collector
dapat diimplementasikan seperti ini:sumber
Gunakan pendekatan ini untuk menjumlahkan daftar BigDecimal:
Pendekatan ini memetakan masing-masing BigDecimal sebagai BigDecimal saja dan menguranginya dengan menjumlahkannya, yang kemudian dikembalikan menggunakan
get()
metode.Berikut cara mudah lain untuk melakukan penjumlahan yang sama:
Memperbarui
Jika saya menulis ekspresi kelas dan lambda dalam pertanyaan yang diedit, saya akan menulisnya sebagai berikut:
sumber
.map(n -> n)
berguna di sana? Jugaget()
tidak diperlukan.get()
karena mengembalikan nilaiOptional
yang dikembalikan olehreduce
panggilan. Jika seseorang ingin bekerja denganOptional
atau hanya mencetak jumlahnya, maka ya,get()
tidak diperlukan. Tapi mencetak Opsional langsung mencetakOptional[<Value>]
sintaksis yang saya ragu pengguna akan perlu. Jadiget()
diperlukan cara untuk mendapatkan nilai dariOptional
.get
panggilan tanpa syarat ! Jikavalues
daftar kosong, opsional tidak akan berisi nilai dan akan membuangNoSuchElementException
ketikaget
dipanggil. Anda bisa menggunakannyavalues.stream().reduce(BigDecimal::add).orElse(BigDecimal.ZERO)
.Jika Anda tidak keberatan dengan ketergantungan pihak ketiga, ada kelas bernama Collectors2 di Eclipse Collections yang berisi metode pengembalian Kolektor untuk menjumlahkan dan merangkum BigDecimal dan BigInteger. Metode ini menggunakan Function sebagai parameter sehingga Anda bisa mengekstraksi nilai BigDecimal atau BigInteger dari objek.
Catatan: Saya pengendara untuk Eclipse Collections.
sumber