«1. Обзор

Vavr — это библиотека расширения объектно-функционального языка с открытым исходным кодом для Java 8+. Это помогает уменьшить объем кода и повысить надежность.

В этой статье мы узнаем об инструменте Vavr под названием «Либо». Если вы хотите узнать больше о библиотеке Vavr, прочтите эту статью.

2. Что такое любой?

В мире функционального программирования функциональные значения или объекты не могут быть изменены (т.е. в нормальной форме); в терминологии Java это известно как неизменяемые переменные.

Либо представляет значение двух возможных типов данных. Либо это либо Левый, либо Правый. По соглашению, левое значение означает неудачный результат, а правое — успешное.

3. Зависимости Maven

Нам нужно добавить следующую зависимость в pom.xml:

<dependency>
    <groupId>io.vavr</groupId>
    <artifactId>vavr</artifactId>
    <version>0.9.0</version>
</dependency>

Последняя версия Vavr доступна в центральном репозитории Maven.

4. Варианты использования

Давайте рассмотрим вариант использования, в котором нам нужно создать метод, который принимает входные данные и, на основе входных данных, возвращает либо строку, либо целое число.

4.1. Обычная Java

Мы можем реализовать это двумя способами. Либо наш метод может возвращать карту с ключом, представляющим результат успеха/неудачи, либо он может возвращать список/массив фиксированного размера, где позиция обозначает тип результата.

Вот как это могло бы выглядеть:

public static Map<String, Object> computeWithoutEitherUsingMap(int marks) {
    Map<String, Object> results = new HashMap<>();
    if (marks < 85) {
        results.put("FAILURE", "Marks not acceptable");
    } else {
        results.put("SUCCESS", marks);
    }
    return results;
}

public static void main(String[] args) {
    Map<String, Object> results = computeWithoutEitherUsingMap(8);

    String error = (String) results.get("FAILURE");
    int marks = (int) results.get("SUCCESS");
}

Для второго подхода мы могли бы использовать следующий код:

public static Object[] computeWithoutEitherUsingArray(int marks) {
    Object[] results = new Object[2];
    if (marks < 85) {
        results[0] = "Marks not acceptable";
    } else {
        results[1] = marks;
    }
    return results;
}

Как мы видим, оба способа требуют довольно много работы, и конечный результат не очень эстетичен и небезопасен в использовании.

4.2. С помощью Both

Теперь давайте посмотрим, как мы можем использовать утилиту Choose от Vavr для достижения того же результата:

private static Either<String, Integer> computeWithEither(int marks) {
    if (marks < 85) {
        return Either.left("Marks not acceptable");
    } else {
        return Either.right(marks);
    }
}

Нет, не требуется явного приведения типов, проверки нулей или создания неиспользуемых объектов.

Кроме того, Both предоставляет очень удобный монадический API для работы в обоих случаях:

computeWithEither(80)
  .right()
  .filter(...)
  .map(...)
  // ...

По соглашению, левый атрибут Both представляет случай неудачи, а Right — успех. Однако, в зависимости от наших потребностей, мы можем изменить это с помощью проекций — Либо в Vavr не смещается влево или вправо.

Если мы спроецируем вправо, такие операции, как filter(), map() не будут иметь никакого эффекта, если в поле Both выбрано Left.

Например, создадим правую проекцию и определим над ней некоторые операции:

computeWithEither(90).right()
  .filter(...)
  .map(...)
  .getOrElse(Collections::emptyList);

Если окажется, что мы спроецировали слева направо, то сразу получим пустой список.

Аналогичным образом можно взаимодействовать с левой проекцией:

computeWithEither(9).left()
  .map(FetchError::getMsg)
  .forEach(System.out::println);

4.3. Дополнительные функции

Доступно множество утилит для работы с любым из них; давайте посмотрим на некоторые из них.

Мы можем проверить, содержит ли объект Both только Left или Right, используя методы isLeft и isRight:

result.isLeft();
result.isRight();

Мы можем проверить, содержит ли объект Both заданное значение Right:

result.contains(100)

один распространенный тип:

Either<String, Integer> either = Either.right(42);
String result = either.fold(i -> i, Object::toString);

или… даже поменять местами стороны:

Either<String, Integer> either = Either.right(42);
Either<Integer, String> swap = either.swap();

5. Заключение

В этом кратком руководстве мы узнали об использовании утилиты Does из платформы Vavr. Более подробную информацию о любом из них можно найти здесь.

Как всегда, полный исходный код доступен на GitHub.