使用java 8划分对象列表中的bigdecimal值?

时间:2017-05-23 21:02:44

标签: java lambda java-8 java-stream

我有一个Invoice对象列表,其中包含属性频率和数量(BigDecimal)。

1)需要在不考虑精度的情况下,根据频率乘以和改变量。在下面显示的代码中输出但是输出失去了一些精度。金额值应为100。

2)是否可以使用java 8 stream API替换发票列表中的金额值。  尝试使用

.Designer.cs

但这不会替换对象中的金额值。 在这种情况下无法弄清楚使用replaceAll,尝试下面的代码,但是给出了编译错误,

invoiceList.forEach(s -> s.getAmount().multiply(new BigDecimal("10")));

整个主要课程如下。无法更改任何数据类型或设计。我必须从Web服务处理获取的列表。

 newList.replaceAll((v) -> v.getAmount().multiply(frequencyFactor.get(v.getFrequency())));

OUTPUT是:

public class InvoiceMain {
    public static void main(String[] args) {
        List<Invoice> invoiceList = Arrays.asList(new Invoice("Quarterly", new BigDecimal(300)), new Invoice("Annually", new BigDecimal(1200)));
        Map<String, BigDecimal> frequencyFactor = new HashMap<>();
        frequencyFactor.put("Annually", new BigDecimal(1.0 / 12));
        frequencyFactor.put("Quarterly", new BigDecimal(1.0 / 3));
        for (Invoice invoice : invoiceList) {
            invoice.setAmount(invoice.getAmount().multiply(frequencyFactor.get(invoice.getFrequency())));
        }
        System.out.println(invoiceList);
    }
}

class Invoice {
    private String frequency;
    private BigDecimal amount;

    public Invoice(String frequency, BigDecimal amount) {
        super();
        this.frequency = frequency;
        this.amount = amount;
    }

    public String getFrequency() {
        return frequency;
    }

    public void setFrequency(String frequency) {
        this.frequency = frequency;
    }

    public BigDecimal getAmount() {
        return amount;
    }

    public void setAmount(BigDecimal amount) {
        this.amount = amount;
    }

    @Override
    public String toString() {
        return "Invoice [frequency=" + frequency + ", amount=" + amount + "]";
    }
}

必需的输出是

[Invoice [frequency=Quarterly, amount=99.999..], Invoice [frequency=Annually, amount=99.999...]]

5 个答案:

答案 0 :(得分:6)

缺陷是使用带有double的BigDecimal构造函数。然后BigDecimal无法确定精度并使用一个适合double的精度,也会引入一个inprecise值(来自double)。

new BigDecimal(1.0/12)

使用divideBy将最佳状态更改为12:使用Map<String, BigDecimal> divisors = ... divisors.put("Anually", BigDecimal.valueOf(12)); ... final Map<String, BigDecimal> finalDivisors = divisors; BigDecimal sum = invoiceList.stream() .map(inv -> inv.amount.divideBy(finalDivisors.get(inv.frequency)) .sum();

static class Invoice {
    final BigDecimal amount;
    final int months;

    Invoice(BigDecimal amount, int months) {
        this.amount = amount;
        this.months = months;
    }
}

public static void main(String[] args) {
    List<Invoice> invoices = Arrays.asList(
            new Invoice(new BigDecimal("12.50"), 3),
            new Invoice(new BigDecimal("120.50"), 12),
            new Invoice(new BigDecimal("7.25"), 3));
    BigDecimal sum = invoices.stream()
            .map(inv -> inv.amount.divide(BigDecimal.valueOf(inv.months),
                                          RoundingMode.HALF_UP))
            .reduce(BigDecimal.ZERO, BigDecimal::add);

    System.out.println("Sum: " + sum); // 16.63
}

在实际代码中:

{{1}}

答案 1 :(得分:4)

使用枚举的替代解决方案。

    public enum Frequency {
        ANUALLY(12), QUARTERLY(3);

        private final int divideBy;

        Frequency(final int div) { this.divideBy = div; }

        public int getDivideBy() { return this.divideBy; }
    }

    public class InvoiceMain {

        public static void main(String[] args) {
        List<Invoice> invoiceList = Arrays.asList(new Invoice(Frequency.QUARTERLY,new     BigDecimal(300)), new Invoice(Frequency.ANUALLY, new BigDecimal(1200)));
        for(Invoice invoice: invoiceList) {
            invoice.setAmount(invoice.getAmount().divide(invoice.getFrequency().getDivideBy())));
        }
        System.out.println(invoiceList);
    }
}


class Invoice {
private Frequency frequency;
private BigDecimal amount;
public Invoice(Frequency frequency, BigDecimal amount) {
    super();
    this.frequency = frequency;
    this.amount = amount;
}
public Frequency getFrequency() {
    return frequency;
}
public void setFrequency(Frequency frequency) {
    this.frequency = frequency;
}
public BigDecimal getAmount() {
    return amount;
}
public void setAmount(BigDecimal amount) {
    this.amount = amount;
}
@Override
public String toString() {
    return "Invoice [frequency=" + frequency + ", amount=" + amount + "]";
}

}

答案 2 :(得分:1)

您好我不确定您是否已经解决了问题,但如果您使用Double而不是BigDezimal,我会得到正确的输出,我试着这样:

public class InvoiceMain {
public static void main(String[] args) {
    List<Invoice> invoiceList = Arrays.asList(new 
    Invoice("Quarterly",300.0),new Invoice("Annually", 1200.0));            
    Map<String, Double> frequencyFactor = new HashMap<>();
    frequencyFactor.put("Annually", (Double)(1.0 / 12));
    frequencyFactor.put("Quarterly",(Double)(1.0 / 3));
    for (Invoice invoice : invoiceList) {
        switch (invoice.getFrequency()) {
        case "Quarterly": // divide by 4, to convert to Monthly
        invoice.setAmount(invoice.getAmount() *
(frequencyFactor.get(invoice.getFrequency())));    
            break;
        case "Annually": // divide by 12, to convert to Monthly
            invoice.setAmount(invoice.getAmount() * 
(frequencyFactor.get(invoice.getFrequency())));
            break;
        }
    }
    System.out.println(invoiceList);
 }
}

class Invoice {
private String frequency;
private Double amount;

public Invoice(String frequency, Double amount) {
    super();
    this.frequency = frequency;
    this.amount = amount;
}

public String getFrequency() {
    return frequency;
}

public void setFrequency(String frequency) {
    this.frequency = frequency;
}

public double getAmount() {
    return amount;
}

public void setAmount(Double amount) {
    this.amount = amount;
}

@Override
public String toString() {
    return "Invoice [frequency=" + frequency + ", amount=" + amount + "]";
}
}

以下是输出:
[发票[频率=季度,金额= 100.0],发票[频率=每年,金额= 100.0]]

干杯,
凯博

答案 3 :(得分:1)

在阅读其他答案后,我发现您真正想要的是计算每月 Invoice,您可以引入Value Object Invoice&amp;枚举Frequency在这里根据OO方式制作代码并且更简单:

enum Frequency {
    ANUALLY(12), QUARTERLY(3), MONTHLY(1);

    private final int months;

    Frequency(final int months) {
        this.months = months;
    }

    private BigDecimal monthly(BigDecimal amount) {
        return amount.divide(BigDecimal.valueOf(months));
    }
}

class Invoice {
    private Frequency frequency;
    private BigDecimal amount;

    public Invoice(Frequency frequency, BigDecimal amount) {
        this.frequency = frequency;
        this.amount = amount;
    }

    private Invoice monthly() {
        return new Invoice(Frequency.MONTHLY, frequency.monthly(this.amount));
    }

    // getters are ignored here
    @Override
    public String toString() {
        return "Invoice [frequency=" + frequency + ", amount=" + amount + "]";
    }
}

那么您的主要课程可以使用如下的流API:

class InvoiceMain {
    public static void main(String[] args) {
        List<Invoice> invoiceList = Arrays.asList(
                new Invoice(Frequency.QUARTERLY, new BigDecimal(300)),
                new Invoice(Frequency.ANUALLY, new BigDecimal(1200))
        );

        System.out.println(invoiceList.stream().map(Invoice::monthly)
                                               .collect(Collectors.toList()));
    }
}

输出

[
  Invoice [frequency=MONTHLY, amount=100],
  Invoice [frequency=MONTHLY, amount=100]
]

答案 4 :(得分:0)

阅读完回复后,我修改了频率因子值,并将乘法乘以除以。

Map<String,BigDecimal> frequencyFactor = new HashMap<>();
    frequencyFactor.put("Monthly", BigDecimal.valueOf(1));
    frequencyFactor.put("Annually",BigDecimal.valueOf(12));
    frequencyFactor.put("Yearly", BigDecimal.valueOf(12));
    frequencyFactor.put("Quaterly", BigDecimal.valueOf(3));
    frequencyFactor.put("Semiannually", BigDecimal.valueOf(6));

    for (Subscription invoice : newList) {
        invoice.setAmount(invoice.getAmount().divide(frequencyFactor.get(invoice.getFrequency()),2,RoundingMode.HALF_UP));
}
    newList.forEach(s-> System.out.println(s));