Рубрики
Без рубрики

Быть более функциональным в java с различными

С выпуском java 8 в разработке с java была обнаружена новая парадигма, но вопрос… Помеченный как java, var, функциональный, программирование.

С выпуском java 8 была открыта новая парадигма в разработке с java, но возникает вопрос – достаточно ли этого? А что, если бы у нас были другие функциональные возможности более чисто функциональных языков в java? Для удовлетворения этих потребностей был изобретен vary с целью сокращения кода, повышения его читабельности и повышения надежности за счет неизменности данных. И в этой статье мы увидим, как быть более функциональными в java с помощью var .

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

Функции

Композиция

С появлением java 8 была включена концепция функции и функции Bi, с помощью которых мы можем определять функции одного или двух входных параметров, например:

Function pow = (n) -> n * n;
assertThat(pow.apply(2)).isEqualTo(4);

BiFunction multiply = (a, b) -> a * b;
assertThat(multiply.apply(10, 5)).isEqualTo(50);

С помощью vavr мы можем иметь функции до 8 параметров с типами функций

Function1 pow = (n) -> n * n;
assertThat(pow.apply(2)).isEqualTo(4);

Function3 multiply = (n1, n2, n3) -> n1 * n2 * n3;
assertThat(multiply.apply(5, 4, 3)).isEqualTo(60);

Помимо возможности создавать функции до 8 входных параметров, он также предлагает нам состав функций с операциями . .а Потом .применить и

Function1 toUpper = String::toUpperCase;
Function1 trim = String::trim;
Function1 cheers = (s) -> String.format("Hello %s", s);
assertThat(trim
            .andThen(toUpper)
            .andThen(cheers)
            .apply("   john")).isEqualTo("Hello JOHN");

Function1 composedCheer = cheers.compose(trim).compose(toUpper);
assertThat(composedCheer.apply(" steve ")).isEqualTo("Hello STEVE");

Поднимание

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

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

Function1 toUpper = (s) -> {
    if (s.isEmpty()) throw new IllegalArgumentException("input can not be null");
    return s.toUpperCase();
};
Function1 trim = String::trim;
Function1 cheers = (s) -> String.format("Hello %s", s);
Function1 composedCheer = cheers.compose(trim).compose(toUpper);

Function1> lifted = Function1.lift(composedCheer); assertThat(lifted.apply("")).isEqualTo(Option.none());
assertThat(lifted.apply(" steve ")).isEqualTo(Option.some("Hello STEVE"));

Частичное применение

С помощью частичного приложения мы можем создать новую функцию, установив n параметров для существующей, где n всегда будет меньше, чем арность исходной функции, а возвращаемый результат будет исходной функцией арности – набор параметров

Function2 cheers = (s1, s2) -> String.format("%s %s", s1, s2);
Function1 sayHello = cheers.apply("Hello");
Function1 sayHola = cheers.apply("Hola");

assertThat(sayHola.apply("Juan")).isEqualTo("Hola Juan");
assertThat(sayHello.apply("John")).isEqualTo("Hello John");

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

Каррирование

Каррирование – это метод разложения функции из нескольких аргументов на последовательность функций аргумента.

 Function3 sum = (a, b, c) -> a + b + c;

        Function1> add2 = sum.curried().apply(2);

        Function1 add2And3 = add2.curried().apply(3);
        assertThat(add2And3.apply(4)).isEqualTo(9);

Запоминание

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

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

void memoization() {
        Function1 calculate = 
            Function1.of(this::aVeryExpensiveMethod).memoized();

        long startTime = System.currentTimeMillis();
        calculate.apply(40);
        long endTime = System.currentTimeMillis();
        assertThat(endTime - startTime).isGreaterThanOrEqualTo(5000l);

        startTime = System.currentTimeMillis();
        calculate.apply(40);
        endTime = System.currentTimeMillis();
        assertThat(endTime - startTime).isLessThan(5000l);


        startTime = System.currentTimeMillis();
        calculate.apply(50);
        endTime = System.currentTimeMillis();
        assertThat(endTime - startTime).isGreaterThanOrEqualTo(5000l);

    }

    private Integer aVeryExpensiveMethod(Integer number) {
        try {
            Thread.sleep(5000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return number * number;
    }

Монады

Попробуй

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

Некоторые полезные методы этой попытки следующие:

.Успех () -> как следует из самого названия, возвращает логическое значение, проверяя, выполнено ли оно успешно.

.Неудача () -> возвращает логическое значение, проверяя, является ли оно ошибкой.

get () -> получить значение в случае, если оно прошло правильно, если выполнено получение и оно не проверено, если оно выполнено без проверки, является ли оно успешным, исключение будет удалено.

map () -> сопоставьте значение в случае, если все прошло хорошо, если это сбой, он не будет выполнен.

getOrElse (T) -> который позволяет возвращать значение по умолчанию в случае ошибки.

getOrElse (Поставщик) -> который позволяет передать другую функцию в случае ошибки.

восстановить (можно выбросить -> {}) – > То же, что и getOrElse, но в этом случае у нас будет исключение, которое было создано, чтобы иметь возможность его достичь или иметь возможность возвращать разные значения в зависимости от типа исключения.

Function2 divide = (n1, n2) -> n1 / n2;

assertThat(Try.of(() -> divide.apply(10, 0)).isFailure()).isTrue();

assertThat(Try.of(() -> divide.apply(10, 5)).isSuccess()).isTrue();

assertThat(Try.of(() -> divide.apply(10, 5)).get()).isEqualTo(2);

assertThat(Try.of(() -> divide.apply(10, 0)).getOrElse(0)).isEqualTo(0);

Ленивый

Ленивый – это монада о Поставщике, к которому применяется запоминание при первой оценке.

Lazy> lazyOperation = Lazy.of(this::getAllActiveUsers);
assertThat(lazyOperation.isEvaluated()).isFalse();
assertThat(lazyOperation.get()).isNotEmpty();
assertThat(lazyOperation.isEvaluated()).isTrue();

Любой

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

Всегда результат будет левым или правым, никогда не может быть так, чтобы они были и тем, и другим.

Структуры данных

Неизменяемые списки

Если одним из принципов функционального программирования является неизменяемость, что происходит, когда мы определяем список и добавляем элементы? Что ж, мы его мутируем.

Var предоставляет специализацию списка, который после создания не может быть изменен, любая операция добавления, удаления, замены даст нам новый экземпляр с примененными изменениями.

import io.vavr.collection.List;
...

//Append
List original = List.of(1,2,3);
List newList = original.append(4);
assertThat(original.size()).isEqualTo(3);
assertThat(newList.size()).isEqualTo(4);

//Remove
List original = List.of(1, 2, 3);
List newList = original.remove(3);
assertThat(original.size()).isEqualTo(3);
assertThat(newList.size()).isEqualTo(2);

//Replace
List original = List.of(1, 2, 4);
List newList = original.replace(4,3);
assertThat(original).contains(1,2,4);
assertThat(newList).contains(1,2,3);

Помимо неизменности, он также предоставляет прямые методы для работы со списком без прохождения потока, получения минимального, максимального, среднего значения .. для получения дополнительной информации о том, что предлагает вам этот список, проверьте javadoc .

И это основные функции, которые предлагает нам Vary, однако есть еще некоторые, которые помогают нам быть более функциональными на таком языке, как java, с помощью vavr.

Первоначально опубликовано на Апиумхаб

Оригинал: “https://dev.to/jcaromiq/be-more-functional-in-java-with-vavr-1ig2”