Будьте обережні з методом Java Optional
Джерело:
Dev.to Згідно 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 вам необхідно:
- Порівняти кожне замовлення зі списком продуктів.
- Відобразити кожному за продукту його ціну.
- Підсумовувати усі ціни, склавши їх одна з одною.
Отже, зробимо це на 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);
}
}
- Створюємо потік замовлень.
- Порівнюємо кожне замовлення з його списком продуктів.
- Порівнюємо кожен список продуктів із потоком. Зверніть увагу, що тут довелося використовувати flatMap , інакше ми отримаємо Stream <Stream <Product>> .
- Відображаємо для кожного товару його ціну.
- Підсумовуємо всі ціни.
- Якщо список замовлень ( 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 .
ПЕРЕЙДІТЬ В ПОВНУ ВЕРСІЮ