简体   繁体   English

通过每次使用不同的 BigDecimal 属性改进 Map/Reduce lambda 表达式

[英]Improve Map/Reduce lambda expression by using a different BigDecimal attribute each time

I have a list of objects and each element of that list is an object that contains several BigDecimal parameters.我有一个对象列表,该列表的每个元素都是一个包含多个 BigDecimal 参数的 object。 I'm generating a new Amount object based on some calculations made on the list.我正在根据列表中的一些计算生成一个新的 Amount object。 It works fine but looks kind of repetitive.它工作正常,但看起来有点重复。

new Amount()
            .withAmountIncVat(invoiceLines.stream().map(line -> line.getAmount().getAmountIncVat()).reduce(BigDecimal.ZERO, BigDecimal::add).setScale(2, RoundingMode.HALF_UP))
            .withAmount(invoiceLines.stream().map(line -> line.getAmount().getAmount()).reduce(BigDecimal.ZERO, BigDecimal::add).setScale(2, RoundingMode.HALF_UP))
            .withVatAmount(invoiceLines.stream().map(line -> line.getAmount().getVatAmount()).reduce(BigDecimal.ZERO, BigDecimal::add).setScale(2, RoundingMode.HALF_UP))

Is there a better way to deal with the lambda expression in order to replace the "repeated" code?是否有更好的方法来处理 lambda 表达式以替换“重复”代码? You know, improve this function:你知道,改进这个 function:

invoiceLines.stream().map(line -> line.getAmount().XXX).reduce(BigDecimal.ZERO, BigDecimal::add).setScale(2, RoundingMode.HALF_UP)

In which XXX should be a different BigDecimal attribute from the object each time, and i can use this function for each assignment:其中 XXX 每次都应该是与 object 不同的 BigDecimal 属性,我可以将这个 function 用于每个分配:

new Amount()
    .withVatAmount(function.apply(invoiceLines,<PERHAPS AN ADDITIONAL PARAM>))
    .withAmountIncVat(function.apply(invoiceLines,<PERHAPS AN ADDITIONAL PARAM>))
    .withAmount(function.apply(invoiceLines,<PERHAPS AN ADDITIONAL PARAM>))

Since operations, you perform in these stream-pipelines differs only with a function extracting BigDecimal value, to avoid redundancy you can introduce a method expecting a source List and a function as its arguments.由于操作,您在这些流管道中执行的操作仅与提取BigDecimal值的 function 不同,为避免冗余,您可以引入一种期望源Listfunction作为其 ZDBC11CAA5BDA8882E4

Note that keeping your functions small and well-readable makes the code more maintainable.请注意,使您的函数保持小而易读使代码更易于维护。 And it's also better to have a code that consumes a function and uses it internally than invoking Function.apply() manually.与手动调用Function.apply()相比,使用 function在内部使用它的代码也更好。

That's how the method containing your stream logic might be implemented:这就是包含您的 stream 逻辑的方法可以如何实现的方式:

public static <T> BigDecimal reduce(List<T> list,
                                    Function<T, BigDecimal> mapper) {
    return list.stream()
        .map(mapper)
        .reduce(BigDecimal.ZERO, BigDecimal::add)
        .setScale(2, RoundingMode.HALF_UP);
}

The code responsible for instantiation and infantilization of the Amount would look like that:负责Amount的实例化和幼稚化的代码如下所示:

new Amount()
    .withAmountIncVat(reduce(invoiceLines, line -> line.getAmount().getAmountIncVat()))
    .withAmount(reduce(invoiceLines, line -> line.getAmount().getAmount()))
    .withVatAmount(reduce(invoiceLines, line -> line.getAmount());

Alexander Ivanchenko's answer can be made a bit simpler by making it less generic.亚历山大·伊万琴科的答案可以通过使其不那么通用而变得更简单一些。 Assuming that line is an instance of Line and its getAmount() method returns an Amount (replace these as necessary):假设lineLine的一个实例,并且它的getAmount()方法返回一个Amount (根据需要替换它们):

private static BigDecimal reduce(List<Line> lines, Function<Amount, BigDecimal> mapper) {
    return lines.stream()
            .map(Line::getAmount)
            .map(mapper)
            .reduce(BigDecimal.ZERO, BigDecimal::add)
            .setScale(2, RoundingMode.HALF_UP);
}
new Amount()
        .withAmountIncVat(reduce(invoiceLines, Amount::getAmountIncVat))
        .withAmount(reduce(invoiceLines, Amount::.getAmount))
        .withVatAmount(reduce(invoiceLines, Amount::getVatAmount);

I just tried out to create such a reusable function and I think I found a way to do it.我刚刚尝试创建这样一个可重复使用的 function,我想我找到了一种方法。 I used the BiFunction interface that defines a function with two inputs.我使用了BiFunction接口,它定义了一个带有两个输入的 function。 In your case it would be the list as well as a function to extract the needed BigDecimal from the Amount object.在您的情况下,它将是列表以及 function 从Amount object 中提取所需的BigDecimal

The result should be the same as with your original code:结果应该与您的原始代码相同:

BiFunction<List<Line>, Function<Line, BigDecimal>, BigDecimal> function =
        (list, extractor) -> list.stream().map(extractor)
            .reduce(BigDecimal.ZERO, BigDecimal::add)
            .setScale(2, RoundingMode.HALF_UP);

new Amount().withVatAmount(function
        .apply(invoiceLines, line -> line.getAmount().getVatAmount()));

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 如何使用使用.map lambda表达式的操作每次使用与列表不同的值? - How do I apply an operation using .map lambda expression using a different value from a list each time? 如何改善地图 <Integer, Map<Integer, Map<PAXType, BigDecimal> &gt;&gt;使用番石榴 - how can i improve upon Map<Integer, Map<Integer, Map<PAXType, BigDecimal>>> using guava 如何使用Lambda表达式减少给定列表.reduce()方法 - How to reduce given list by using Lambda expression .reduce() method 了解Java 8/9功能编程中的Map and Reduce(lambda表达式)。 map()和reduce()如何提高性能? - Understanding Map and Reduce in Java 8/9 functional programming (lambda expression). How map() and reduce() increases performance? 使用Lambda表达式将列表转换为地图不起作用 - Converting List to Map using Lambda Expression Not working 如何在Java中使用Lambda表达式添加地图 - How to add Map using lambda expression in java 使用 Java 8 Lambda 表达式合并 Map 流 - Merging Map streams using Java 8 Lambda Expression 使用来自不同类层次结构路由的两个字段进行map-filter lambda表达式 - Using two fields from different class hierarchy routes for map-filter lambda expression 使用reduce方法在Stream中添加BigDecimal - Adding BigDecimal in Stream using reduce method 需要使用lambda映射多个文件中的减少行 - Need to map reduce lines in multiple files using lambda
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM