Be careful with the Java Optional method
Source:
Dev.to According to Oracle, an Optional object is “a container object that may or may not contain a non-null value.” Optional first appeared in Java 8 and has been used by the SpringBoot team in many projects. The most common use of
Optionals is in a Spring Data project. Let's look at the JpaRepository interface and an example method. For example, we have a
User object with an integer type Id and we have a JpaRepository for it.
@Repository
public interface IUserRepo extends JpaRepository<User, Integer>
{
Optional<User> findByUserName(String userName);
}
We've defined a method that looks up a user by their name and returns
an Optional for
User .
Convenient Methods Optional
Optional is included in many methods that allow us to write clean and readable code.
However, there is one method with dangerously unexpected behavior.
Meet the orElse method
According to Oracle documentation:
public T orElse(T other)
Return the value if there is one, otherwise return something else. Now we can add a method call as an
orElse parameter that will run if the
Optional parameter is empty, right? Yes, that's correct, but what if I told you that it will work anyway, regardless of whether there is a value in
Optional or not. Let's check:
@Test
public void orElseTest()
{
String result = Optional.of("hello").orElse(someMethod());
assertThat(result).isEqualTo("hello");
}
private String someMethod()
{
System.out.println("I am running !!");
return "hola";
}
The test was successful, but you will notice that the line “
I am running ” is printed on the console.
Why is this happening?
Java runs a method to provide the value that will be returned in the case of
Else .
So be careful!
You have to be careful if a method inside
orElse might have a side effect because it will still be run.
What to do?
You can use the
OrElseGet method , which takes a supplier method to execute if
Optional exists .
How to display and sum elements from a list in Java
Source:
DZone In this post, you will learn how to display and summarize the number of elements from a list in Java. Mapping items from a List
means that each item in that list will be converted to a different object. Summing elements from a list means that all elements from that list will be combined into one object, which is not necessarily the same type as the original one. Let's say we have a list of orders, and each order has a list of products.
record Order(String customer, List<Product> products) {
}
record Product(String brand, String modelName, BigDecimal price) {
}
What would you do if you wanted to know how much money was coming from an order list? For each order, you will need to get a list of the products present in it, and for each product in these lists, you will need to get its cost. After that, you need to sum up all these prices, and this is how you get the result. When translating the above to
Map /
Reduce you need:
- Match each order with a product list.
- Display the price for each product.
- Sum up all prices by adding them together.
So let's do it in Java:
public class OrderMapReducer {
public BigDecimal getTotal(List<Order> orders) {
return orders.stream()
.map(Order::products)
.flatMap(List::stream)
.map(Product::price)
.reduce(BigDecimal::add)
.orElse(BigDecimal.ZERO);
}
}
- We create a flow of orders.
- We match each order with its product list.
- We match each product list with a flow. Note that we had to use flatMap here , otherwise we would end up with Stream <Stream <Product>> .
- For each product we display its price.
- Let's sum up all the prices.
- If the Order List is empty, return zero.
That's all! Now we can create a test to make sure everything is working as expected.
@Test
void getTotalPrice() {
List<Order> orders = createOrders();
OrderMapReducer orderMapReducer = new OrderMapReducer();
assertEquals(new BigDecimal(17800), orderMapReducer.getTotal(orders));
}
private static List<Order> createOrders() {
var strato = new Product("Fender", "Stratocaster", new BigDecimal(3500));
var sg = new Product("Gibson", "SG", new BigDecimal(4800));
var lesPaul = new Product("Gibson", "Les Paul", new BigDecimal(4500));
var rr = new Product("Jackson", "RR", new BigDecimal(5000));
return List.of(
new Order("David Gilmour", List.of(strato)),
new Order("Toni Iommi", List.of(sg)),
new Order("Randy Rhoads", List.of(lesPaul, rr))
);
}
As you can see, Map and Reduce helps in cases where you need to extract information from
a Collection .
GO TO FULL VERSION