JavaRush /Java блог /Random /Кофе-брейк #97. Будьте осторожны с методом Java Optional....

Кофе-брейк #97. Будьте осторожны с методом Java Optional. Как отображать и суммировать элементы из списка в Java

Статья из группы Random

Будьте осторожны с методом Java Optional

Источник: Dev.to Кофе-брейк #97. Будьте осторожны с методом Java Optional. Как отображать и суммировать элементы из списка в Java - 1Согласно Oracle, объект Optional — это “объект-контейнер, который может содержать или не содержать значение non-null”. Optional впервые появился в Java 8 и использовался командой SpringBoot во многих проектах. Чаще всего Optionals используется в проекте Spring Data. Давайте посмотрим на интерфейс JpaRepository и пример метода. Например, у нас есть объект User с целочисленным типом Id и для него есть JpaRepository.

@Repository  
public interface IUserRepo extends JpaRepository<User, Integer>  
{  
    Optional<User> findByUserName(String userName);  
}
Мы определили метод, который ищет пользователя по его имени и возвращает Optional для User.

Удобные методы Optional

Optional входит в множество методов, которые позволяют нам писать чистый и читаемый код.Однако есть один метод с опасно неожиданным поведением.

Познакомьтесь с методом orElse

Согласно документации Oracle:

public T orElse(T other)
Верните значение, если оно есть, в противном случае верните другое. Теперь мы можем добавить вызов метода в качестве параметра orElse, который будет запущен, если параметр Optional пуст, верно? Да, это правильно, но что, если я скажу вам, что оно будет работать в любом случае, независимо от наличия значения в Optional или нет. Давайте проверим:

@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";  
}
Тест прошел успешно, но можно заметить, что на консоли распечатана строка “I am running”.

Почему так происходит?

Java запускает метод, чтобы предоставить значение, которое будет возвращено в случае Else.

Так что будьте осторожны!

Нужно быть осторожным, если метод внутри orElse может иметь побочный эффект, потому что он все равно будет запущен.

Что же делать?

Вы можете использовать метод OrElseGet, который принимает метод поставщика (supplier method) для выполнения, если существует Optional.

Как отображать и суммировать элементы из списка в Java

Источник: DZone В этой публикации вы узнаете, как из списка в Java отобразить и суммировать количество элементов. Отображение элементов из списка (List) означает, что каждый элемент из этого списка будет преобразован в другой объект. Суммирование элементов из списка означает, что все элементы из этого списка будут объединены в один объект, который не обязательно имеет тот же тип, что и исходный. Допустим, у нас есть список заказов, и в каждом заказе есть список продуктов.

record Order(String customer, List<Product> products) {
}

record Product(String brand, String modelName, BigDecimal price) {
}
Что бы вы сделали, если бы требовалось узнать, сколько денег поступает из списка заказов? Для каждого заказа вам нужно будет получить список присутствующих в нем продуктов, а для каждого продукта в этих списках нужно получить его стоимость. После этого вам требуется суммировать все эти цены, и так вы получите результат. При переводе приведенного выше на Map / Reduce вам необходимо:
  1. Сопоставить каждый заказ со списком продуктов.
  2. Отобразить для каждого продукта его цену.
  3. Суммировать все цены, сложив их друг с другом.
Итак, сделаем это на Java:

public class OrderMapReducer {
    public BigDecimal getTotal(List<Order> orders) {
        return orders.stream() // 1
                     .map(Order::products) // 2
                     .flatMap(List::stream) // 3
                     .map(Product::price) // 4
                     .reduce(BigDecimal::add) // 5
                     .orElse(BigDecimal.ZERO); // 6
    }
}
  1. Создаем поток заказов.
  2. Сопоставляем каждый заказ с его списком продуктов.
  3. Сопоставляем каждый список продуктов с потоком. Обратите внимание, что здесь нам пришлось использовать flatMap, иначе мы получим Stream <Stream <Product>>.
  4. Отображаем для каждого продукта его цену.
  5. Суммируем все цены.
  6. Если список заказов (Order List) пуст, возвращаем zero.
Вот и все! Теперь мы можем создать тест, чтобы убедиться, что все работает должным образом.

@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))
    );
}
Как видите, сопоставление и суммирование (Map and Reduce) помогает в тех случаях, когда вам нужно извлечь информацию из Collection.
Комментарии (2)
ЧТОБЫ ПОСМОТРЕТЬ ВСЕ КОММЕНТАРИИ ИЛИ ОСТАВИТЬ КОММЕНТАРИЙ,
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ
Константин Уровень 40
10 декабря 2021
Прям капец как не нравится регулярное использование автором слова "Сопоставляем". В моем понимании сопоставление объектов - это сродни их сравнению, общему анализу... Тогда как понимать фразы типа "Сопоставляем каждый заказ с его списком продуктов." ??? Возможно автор так пытался перевести метод "map" - тогда я бы предложил вариант "отображаем" - "Отображаем список продуктов для каждого заказа". Что собственно говоря в 4м пункте автор и сделал, после того как 3 раза "сопоставил" Простите если я придрался на ровном месте, но как-то прям вообще теряется смысл фразы. Ну не к месту там вообще слово "сопоставлять".
Павел Уровень 35
25 октября 2021
Про Optional гораздо интереснее статья про школьную доску, а та, что вы перевели, хороша идеей о том, прежде чем в параметр попадет что либо, оно должно вычислиться.