JavaRush /Java блог /Random UA /Кава-брейк #97. Будьте обережні з методом Java Optional. ...

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

Стаття з групи Random UA

Будьте обережні з методом 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 .

Тож будьте обережні!

Потрібно бути обережним, якщо метод всередині абоElse може мати побічний ефект, тому що він все одно буде запущено.

Що ж робити?

Ви можете використовувати метод 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 .
Коментарі
ЩОБ ПОДИВИТИСЯ ВСІ КОМЕНТАРІ АБО ЗАЛИШИТИ КОМЕНТАР,
ПЕРЕЙДІТЬ В ПОВНУ ВЕРСІЮ