#java #lambda #java-8 #java-stream
#java #лямбда #java-8 #java-stream
Вопрос:
Мне нужно отсортировать коллекцию с несколькими условиями. Но между этими условиями мне нужно изменить данные потока.
Customer.class
import java.math.BigDecimal;
import java.util.Date;
public class Customer {
private int id;
private String name;
private long quantity;
private BigDecimal cost;
private Date lastPurchasedDate;
public Customer(int id, String name, long quantity, BigDecimal cost) {
this.id = id;
this.name = name;
this.quantity = quantity;
this.cost = cost;
}
// setters amp; getters are omitted for brevity.
}
Main.class
import java.math.BigDecimal;
import java.util.Arrays;
import java.util.Comparator;
import java.util.List;
import java.util.Optional;
public class Main {
public static void main(String[] args) {
List<Customer> customers = Arrays.asList(new Customer(1, "A", 10, BigDecimal.valueOf(673.89)),new Customer(2, "B", 10, BigDecimal.valueOf(673.89)));
getCustomer(customers).ifPresent(c -> System.out.println(c.getId()));
}
private static Optional<Customer> getCustomer(List<Customer> customers) {
// @formatter:off
return customers.stream()
.max(
Comparator.comparing(Customer::getQuantity)
.thenComparing(Customer::getCost)
// here I need to check, If multiple customers are after
// comparing the cost, I have to update the lastPurchasedDate l
// attribute value amp; then sort it
.thenComparing(Customer::getLastPurchasedDate)
);
// @formatter:on
}
}
Если после сортировки по стоимости доступно несколько клиентов, то мне нужно заполнить значение атрибута lastPurchasedDate, а затем отсортировать его по lastPurchasedDate.
Почему я не заполняю данные lastPurchasedDate раньше?
Чтобы получить эту информацию, мне нужно выполнить запрос в базе данных (чтобы получить информацию, мы собираемся использовать таблицу, в которой будут миллионы записей). Итак, это ограничение производительности, и я хочу этого избежать. Требуется очень редкий сценарий сравнения по lastPurchasedDate. Поэтому я не хочу без необходимости запускать этот запрос для всех клиентов.
Комментарии:
1. Мне нужно заполнить значение атрибута lastPurchasedDate, а затем отсортировать его по lastPurchasedDate. также не очень хорошая идея делать это в качестве промежуточной операции потоков. Вы могли бы также написать собственный
Comparator
.2. Что вы имеете в виду, говоря «затем отсортируйте это»? Вы не сортируете поток, вы извлекаете из него максимального клиента. Наличие функции, которая удаляет одного клиента из списка, а также сортирует его при некоторых условиях, является нарушением принципа единой ответственности для методов.
3. Я бы сделал это в двух или трех потоковых операциях. Сначала выделите те, которые имеют наибольшую стоимость, в отдельный список. Если их больше одного, то измените и используйте новую потоковую операцию для окончательной сортировки.
4. Сначала решите, чего вы действительно хотите, сортировки или получения максимального элемента.
5. @ErwinBolwidt, я считаю, что нам нужно сортировать данные только «при некоторых условиях». Здесь моя функция получит максимального клиента, применив некоторые условия. Как и в случае с первым, мы применим условие количества, если у нескольких клиентов максимальное количество клиентов, затем применим условие стоимости. Мой вопрос касается одного из этих данных, в данном примере заполнение lastPurchasedDate — сложная операция, и я не хочу делать это до тех пор, пока в этом нет необходимости.
Ответ №1:
Это решение, к которому я пришел…
import java.math.BigDecimal;
import java.util.Arrays;
import java.util.Comparator;
import java.util.Date;
import java.util.List;
import java.util.Optional;
public class Main {
public static void main(String[] args) {
List<Customer> customers = Arrays.asList(new Customer(1, "A", 10, BigDecimal.valueOf(673.89)),new Customer(2, "B", 10, BigDecimal.valueOf(673.89)));
getCustomer(customers).ifPresent(c -> System.out.println(c.getId()));
}
private static Optional<Customer> getCustomer(List<Customer> customers) {
// @formatter:off
return customers.stream()
.max(
Comparator.comparing(Customer::getQuantity)
.thenComparing(Customer::getCost)
.thenComparing(Main::updateLastPurchasedDate)
);
// @formatter:on
}
private static Date updateLastPurchasedDate(Customer c) {
Date lastPurchasedDate = customerRepository.getLastPurchasedDateById(c.getId());
if(lastPurchasedDate == null) {
return new Date(10000);
}
return lastPurchasedDate;
}
}