I have a problem with streams. I have many Customer
objects and I would like to calculate which one of them paid the most.
This is my sample data:
class Orders {
private List<Order> orders = new ArrayList<>();
public void prepareData() {
Product socks = new ProductBuilder()
.setPrice(new BigDecimal("23"))
.setCategory(Category.C)
.setName("SOCKS")
.build();
Product jacket = new ProductBuilder()
.setPrice(new BigDecimal("199"))
.setCategory(Category.A)
.setName("JACKET")
.build();
Product watch = new ProductBuilder()
.setPrice(new BigDecimal("100"))
.setCategory(Category.B)
.setName("WATCH CASIO")
.build();
Customer john = new CustomerBuilder()
.setAge(18)
.setName("JOHN")
.setSurname("JOHNSON")
.setEmail("[email protected]")
.build();
Customer mike = new CustomerBuilder()
.setAge(20)
.setName("MIKE")
.setSurname("MAX")
.setEmail("[email protected]")
.build();
Order orderJohn = new OrderBuilder()
.setQuantity(2)
.setCustomer(john)
.setProduct(watch)
.setOrderDate(LocalDate.now())
.build();
Order orderJohn2 = new OrderBuilder()
.setQuantity(4)
.setCustomer(john)
.setProduct(socks)
.setOrderDate(LocalDate.now())
.build();
Order orderMike = new OrderBuilder()
.setQuantity(2)
.setCustomer(mike)
.setProduct(jacket)
.setOrderDate(LocalDate.now())
.build();
orders.add(orderJohn);
orders.add(orderJohn2);
orders.add(orderMike);
}
}
Now I should group by customer because one customer has many orders and calculate price * and quantity and select maximum using orders.stream()
? How can I do that?
My class definitions:
public class Order {
private Customer customer;
private Product product;
private int quantity;
private LocalDate orderDate;
//get/set
}
public class Customer {
private String name;
private String surname;
private int age;
private String email;
//get/set
}
public class Product {
private String name;
private BigDecimal price;
private Category category;
//get/set
}
And builders
public class CustomerBuilder {
private Customer customer = new Customer();
public CustomerBuilder setName(String name){
customer.setName(name);
return this;
}
public CustomerBuilder setSurname(String surname){
customer.setSurname(surname);
return this;
}
public CustomerBuilder setAge(int age){
customer.setAge(age);
return this;
}
public CustomerBuilder setEmail(String email){
customer.setEmail(email);
return this;
}
public Customer build() {
return customer;
}
}
public class OrderBuilder {
private Order order = new Order();
public OrderBuilder setCustomer(Customer customer){
order.setCustomer(customer);
return this;
}
public OrderBuilder setProduct(Product product){
order.setProduct(product);
return this;
}
public OrderBuilder setQuantity(int quantity){
order.setQuantity(quantity);
return this;
}
public OrderBuilder setOrderDate(LocalDate orderDate){
order.setOrderDate(orderDate);
return this;
}
public Order build(){
return order;
}
}
public class ProductBuilder {
private Product product = new Product();
public ProductBuilder setCategory(Category category){
product.setCategory(category);
return this;
}
public ProductBuilder setName(String name){
product.setName(name);
return this;
}
public ProductBuilder setPrice(BigDecimal bigDecimal){
product.setPrice(bigDecimal);
return this;
}
public Product build() {
return product;
}
}
Calling stream() method on the list to get a stream of values from the list. Calling mapToInt(value -> value) on the stream to get an Integer Stream. Calling max() method on the stream to get the max value. Calling orElseThrow() to throw an exception if no value is received from max()
With the introduction of Stream with Java 8, we can convert the array into the corresponding type stream using the Arrays. stream() method. Then we can call the max() and min() method, which returns the maximum and minimum element of this stream as OptionalInt .
Stream. max() returns the maximum element of the stream based on the provided Comparator. A Comparator is a comparison function, which imposes a total ordering on some collection of objects. max() is a terminal operation which combines stream elements and returns a summary result.
Using Stream.collect() The second method for calculating the sum of a list of integers is by using the collect() terminal operation: List<Integer> integers = Arrays. asList(1, 2, 3, 4, 5); Integer sum = integers. stream() .
Stream.max () method in Java with Examples. Stream.max () returns the maximum element of the stream based on the provided Comparator. A Comparator is a comparison function, which imposes a total ordering on some collection of objects. max () is a terminal operation which combines stream elements and returns a summary result.
The traditional way is to create a for-loop to sum up the salary of each employee and then calculate the average by dividing the total sum by number of record. How to achieve it using Java Stream API? It transforms employee records to salary amount in the data stream flow and then calculates the average.
The Stream API provides us with the mapToInt () intermediate operation, which converts our stream to an IntStream object. This method takes a mapper as a parameter, which it uses to do the conversion, then we can call the sum () method to calculate the sum of the stream's elements. Let's see a quick example of how we can use it:
Let me show you the power of the stream API with an example. Say, the task is to group an array of employee records into a data map organized by job title. Here is a traditional way to loop through the list and construct a data map. Java Stream API imply applies the collector to generate data map grouping by employee’s title.
The following finds the top customer by first grouping by the customer
field (mapped to the total of corresponding purchase value [quantity * price
]).
The result of that aggregation is then traversed to find "max" by total purchase value.
Customer topCustomer = orders.stream()
.collect(Collectors.groupingBy(Order::getCustomer,
Collectors.mapping(
order -> order.getProduct()
.getPrice()
.multiply(new BigDecimal(order.getQuantity())),
Collectors.reducing(BigDecimal.ZERO, BigDecimal::add))))
.entrySet().stream()
.max(Comparator.comparing(Entry::getValue))
.map(Entry::getKey)
.orElse(null);
It's important to note that this assumes hashCode()
and equals()
are properly overridden in Customer
for the grouping to work correctly.
EDIT:
If the total amount of purchases is also required, you will need to get the full entry instead of mapping to just the key (below code is based on snippet above):
Optional<Entry<Customer, BigDecimal>> topCustomerEntry = orders.stream()
.collect(Collectors.groupingBy(Order::getCustomer,
Collectors.mapping(order ->
order.getProduct()
.getPrice()
.multiply(new BigDecimal(order.getQuantity())),
Collectors.reducing(BigDecimal.ZERO, BigDecimal::add))))
.entrySet().stream()
.max(Comparator.comparing(Entry::getValue));
BigDecimal topValue = null; //total value for top customer
Customer customer = null; //customer with most purchases
if(topCustomerEntry.isPresent()) {
topValue = topCustomerEntry.get().getValue();
customer = topCustomerEntry.get().getKey();
}
This will just print the values. But you can restructure the code to assign them to a variable.
In case you need the customer which spends the most (by email for example):
orders.stream()
.collect(Collectors.toMap(
x -> x.getCustomer().getEmail(),
x -> x.getProduct().getPrice().multiply(new BigDecimal(x.getQuantity())),
BigDecimal::add))
.entrySet()
.stream()
.max(Entry.comparingByValue())
.ifPresent(System.out::println);
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With