Ряд операций сведения, такие как min, max, reduce, возвращают объект Optional<T>. Этот объект фактически обертывает результат операции. После выполнения операции с помощью метода get() объекта Optional мы можем получить его значение:
import java.util.Optional; import java.util.ArrayList; import java.util.Arrays; public class Program { public static void main(String[] args) { ArrayList<Integer> numbers = new ArrayList<Integer>(); numbers.addAll(Arrays.asList(new Integer[]{1,2,3,4,5,6,7,8,9})); Optional<Integer> min = numbers.stream().min(Integer::compare); System.out.println(min.get()); // 1 } }
Но что, если поток не содержит вообще никаких данных:
// список numbers пустой ArrayList<Integer> numbers = new ArrayList<Integer>(); Optional<Integer> min = numbers.stream().min(Integer::compare); System.out.println(min.get()); // java.util.NoSuchElementException
В этом случае программа выдаст исключение java.util.NoSuchElementException. Что мы можем сделать, чтобы избежать выброса исключения? Для этого класс Optional предоставляет ряд методов.
Самой простой способ избежать подобной ситуации - это предварительная проверка наличия значения в Optional с помощью метода isPresent(). Он возврашает true, если значение присутствует в Optional, и false, если значение отсутствует:
ArrayList<Integer> numbers = new ArrayList<Integer>(); Optional<Integer> min = numbers.stream().min(Integer::compare); if(min.isPresent()){ System.out.println(min.get()); }
Метод orElse() позволяет определить альтернативное значение, которое будет возвращаться, если Optional не получит из потока какого-нибудь значения:
// пустой список ArrayList<Integer> numbers = new ArrayList<Integer>(); Optional<Integer> min = numbers.stream().min(Integer::compare); System.out.println(min.orElse(-1)); // -1 // непустой список numbers.addAll(Arrays.asList(new Integer[]{4,5,6,7,8,9})); min = numbers.stream().min(Integer::compare); System.out.println(min.orElse(-1)); // 4
Метод orElseGet() позволяет задать функцию, которая будет возвращать значение по умолчанию:
import java.util.Optional; import java.util.ArrayList; import java.util.Arrays; import java.util.Random; public class Program { public static void main(String[] args) { ArrayList<Integer> numbers = new ArrayList<Integer>(); Optional<Integer> min = numbers.stream().min(Integer::compare); Random rnd = new Random(); System.out.println(min.orElseGet(()->rnd.nextInt(100))); } }
В данном случае возвращаемое значение генерируется с помощью метода nextInt класса Random, который возвращает случайное число.
Еще один метод - orElseThrow позволяет сгенерировать исключение, если Optional не содержит значения:
ArrayList<Integer> numbers = new ArrayList<Integer>(); Optional<Integer> min = numbers.stream().min(Integer::compare); // генеррация исключения IllegalStateException System.out.println(min.orElseThrow(IllegalStateException::new));
Метод ifPresent() определяет действия со значением в Optional, если значение имеется:
ArrayList<Integer> numbers = new ArrayList<Integer>(); numbers.addAll(Arrays.asList(new Integer[]{4,5,6,7,8,9})); Optional<Integer> min = numbers.stream().min(Integer::compare); min.ifPresent(v->System.out.println(v)); // 4
В метод ifPresent передается функция, которая принимает один параметр - значение из Optional. В данном случае полученное минимальное число выводится на консоль. Но если бы массив numbers был бы пустым, и соответственно Optional не сдержало бы никакого значения, то никакой ошибки бы не было.
Метод ifPresentOrElse() позволяет определить альтернативную логику на случай, если значение в Optional отсутствует:
ArrayList<Integer> numbers = new ArrayList<Integer>(); Optional<Integer> min = numbers.stream().min(Integer::compare); min.ifPresentOrElse( v -> System.out.println(v), () -> System.out.println("Value not found") );
В метод ifPresentOrElse передается две функции. Первая обрабатывает значение в Optional, если оно присутствует. Вторая функция представляет действия, которые выполняются, если значение в Optional отсутствует.