1. Введение
Функциональные интерфейсы
, предоставляемые JDK, не подготовлены должным образом для обработки проверенных исключений. Если вы хотите узнать больше о проблеме, прочтите эту статью.
В этой статье мы рассмотрим различные способы преодоления таких проблем с помощью функциональной Java-библиотеки Vavr .
Чтобы получить больше информации о Vavr и о том, как его настроить, ознакомьтесь с этой статьей .
2. Использование проверенной функции
Vavr предоставляет функциональные интерфейсы
с функциями, которые вызывают проверенные исключения. Это функции CheckedFunction0
, CheckedFunction1
и так далее до CheckedFunction8
. 0, 1 , … 8
в конце имени функции указывают количество входных аргументов для функции.
Давайте посмотрим пример:
static Integer readFromFile(Integer integer) throws IOException {
// logic to read from file which throws IOException
}
Мы можем использовать вышеуказанный метод внутри лямбда-выражения без обработки IOException
:
List<Integer> integers = Arrays.asList(3, 9, 7, 0, 10, 20);
CheckedFunction1<Integer, Integer> readFunction = i -> readFromFile(i);
integers.stream()
.map(readFunction.unchecked());
Как видите, без стандартных методов try-catch
или методов-оболочек мы по-прежнему можем вызывать методы генерации исключений внутри лямбда-выражения.
Мы должны проявлять осторожность при использовании этой функции с Stream
API, так как исключение немедленно прервет операцию, отказавшись от остальной части потока.
3. Использование вспомогательных методов
Класс API предоставляет метод быстрого доступа для примера из предыдущего раздела:
List<Integer> integers = Arrays.asList(3, 9, 7, 0, 10, 20);
integers.stream()
.map(API.unchecked(i -> readFromFile(i)));
4. Использование подъема
Чтобы изящно обрабатывать IOException
, мы можем ввести стандартные блоки try-catch
внутри лямбда-выражения. Однако краткость лямбда-выражения будет потеряна. Нам на помощь приходит подъем Вавра.
Подъем — это концепция функционального программирования. Вы можете поднять частичную функцию до общей функции, которая возвращает Option
в качестве результата.
Частичная функция — это функция, которая определена только для подмножества предметной области, в отличие от полной функции, которая определена для всей своей предметной области. Если частичная функция вызывается с входными данными, выходящими за пределы ее поддерживаемого диапазона, она обычно выдает исключение.
Перепишем пример из предыдущего раздела:
List<Integer> integers = Arrays.asList(3, 9, 7, 0, 10, 20);
integers.stream()
.map(CheckedFunction1.lift(i -> readFromFile(i)))
.map(k -> k.getOrElse(-1));
Обратите внимание, что результатом поднятой функции является Option
, а результатом будет Option.None
в случае исключения. Метод getOrElse()
принимает альтернативное значение для возврата в случае Option.None
.
5. Использование «Попробовать»
Хотя метод lift()
из предыдущего раздела решает проблему внезапного завершения программы, он фактически проглатывает исключение. Следовательно, потребитель нашего метода понятия не имеет, что привело к значению по умолчанию. Альтернативой является использование контейнера Try .
Try
— это специальный контейнер, в который мы можем заключить операцию, которая может вызвать исключение. В этом случае результирующий объект Try представляет собой
ошибку
и оборачивает исключение.
Давайте посмотрим на код, который использует Try
:
List<Integer> integers = Arrays.asList(3, 9, 7, 0, 10, 20);
integers.stream()
.map(CheckedFunction1.liftTry(i -> readFromFile(i)))
.flatMap(Value::toJavaStream)
.forEach(i -> processValidValue(i));
Чтобы узнать больше о контейнере Try
и о том, как его использовать, ознакомьтесь с этой статьей .
6. Заключение
В этой быстрой статье мы показали, как использовать функции библиотеки Vavr, чтобы обойти проблемы при работе с исключениями в лямбда-выражениях.
Хотя эти функции позволяют нам элегантно справляться с исключениями, их следует использовать с особой осторожностью. С некоторыми из этих подходов потребители ваших методов могут быть удивлены неожиданными проверенными исключениями, хотя они явно не объявлены.
Полный исходный код всех примеров в этой статье можно найти на Github .