如何使用stream#sorted()按Java 8中两个字段的乘积进行排序

时间:2017-02-16 20:13:34

标签: java sorting java-stream

我是Java 8中使用lambdas的新手,我在排序方面遇到了麻烦。

基本上,我在一个类中有4个字段,然后在我的main方法中创建一个要排序的对象数组。我希望能够使用Stream#sorted()按2个字段(price * quantity)的乘积对输出进行排序。

这是我想要排序的课程:

public class Invoice {

   private final int partNumber; 
   private final String partDescription;
   private int quantity;
   private double price;

   // constructor
   public Invoice(int partNumber, String partDescription, int quantity, double price) {
      if (quantity < 0) // validate quantity
         throw new IllegalArgumentException("Quantity must be >= 0");

      if (price < 0.0) // validate price
         throw new IllegalArgumentException("Price per item must be >= 0");

      this.partNumber = partNumber;
      this.partDescription = partDescription;
      this.quantity = quantity;
      this.price = price;
   } // end constructor

//get and set accessors 

}

这是我的测试类,包含我的对象数组:

public class ProcessInvoices  {

    public static void main(String[] args) {

      //declare array of invoice objects
      Invoice[] invoices = {
        new Invoice(83, "Electric sander", 7, 57.98),
        new Invoice(24, "Power saw", 18, 99.99),
        new Invoice(7, "Sledge hammer", 11, 21.50),
        new Invoice(77, "Hammer", 76, 11.99),
        new Invoice(39, "Lawn mower", 3, 79.50),
        new Invoice(68, "Screw driver", 106, 6.99),
        new Invoice(56, "Jig saw", 21, 11.00),
        new Invoice(3, "Wrench", 34, 7.50)};

      System.out.println("\nInvoices mapped to description and invoice amount");
      Arrays.stream(invoices)
        .sorted(Comparator.comparing(invoice.getQuantity() * invoice.getPrice()))
        .map(invoice -> String.format("Description: %-15s     Invoice amount:  $%,6.2f", invoice.getPartDescription(), (invoice.getQuantity() * invoice.getPrice())))
        .forEach(invoice -> System.out.printf("%s%n", invoice));

}

在流中,我将partDescription映射到quantityprice的产品,其中包含发票的总价。这是我想要排序的,发票的总价格,但我不知道使用sorted()方法执行此操作的正确方法。

我尝试简单地按quantity * price进行比较,但这告诉我变量“发票无法识别”。如果我尝试在map()语句之后进行排序,那也不起作用。我也试过使用另一个变量amount,也没有运气。

如何使用sorted()

按两个字段的乘积进行排序

3 个答案:

答案 0 :(得分:3)

比较器lambda中有错误,应该读

.sorted(Comparator.comparing(invoice -> invoice.getQuantity() * invoice.getPrice()))

而不是

.sorted(Comparator.comparing(invoice.getQuantity() * invoice.getPrice()))

注意缺少invoice ->

答案 1 :(得分:0)

我强烈建议您在Invoice上创建一个进行计算的方法:

public double getTotalPrice() {
  return quantity * price;
}

这实际上只是面向对象的基本方式。

然后你可以将它用作method reference并避免在lambda中使用逻辑进行排序:

.sorted(Comparator.comparingDouble(Invoice::getTotalPrice))

请注意,您可以使用built-in comparator对双打进行排序。

作为旁注,如果您想BigDecimal,可能需要使用have an exact floating point precision

答案 2 :(得分:-1)

这也可以:

public class InvoiceTest {
    @Test
    public void testName() throws Exception {
        //declare array of invoice objects
        Invoice[] invoices = {
            new Invoice(83, "Electric sander", 7, 57.98),
            new Invoice(24, "Power saw", 18, 99.99),
            new Invoice(7, "Sledge hammer", 11, 21.50),
            new Invoice(77, "Hammer", 76, 11.99),
            new Invoice(39, "Lawn mower", 3, 79.50),
            new Invoice(68, "Screw driver", 106, 6.99),
            new Invoice(56, "Jig saw", 21, 11.00),
            new Invoice(3, "Wrench", 34, 7.50)};

        System.out.println("\nInvoices mapped to description and invoice amount");
        Arrays.stream(invoices).sorted(new Comparator<Invoice>() {
            @Override
            public int compare(Invoice i1, Invoice i2) {
                return Double.valueOf(i1.getQuantity() * i1.getPrice()).compareTo(Double.valueOf(i2.getQuantity() * i2.getPrice()));
           }
        }).map(invoice -> String.format("Description: %-15s     Invoice amount:  $%,6.2f", invoice.getPartDescription(), (invoice.getQuantity() * invoice.getPrice())))
            .forEach(invoice -> System.out.printf("%s%n", invoice));

    }
}