С выпуском java 8 была открыта новая парадигма в разработке с java, но возникает вопрос – достаточно ли этого? А что, если бы у нас были другие функциональные возможности более чисто функциональных языков в java? Для удовлетворения этих потребностей был изобретен vary с целью сокращения кода, повышения его читабельности и повышения надежности за счет неизменности данных. И в этой статье мы увидим, как быть более функциональными в java с помощью var .
Vavr, помимо прочего, включает неизменность списков и функций для работы с ними, а также некоторые монады, наиболее часто используемые в других языках, более функциональные, каррирующие и частичные приложения в функциях.
Функции
Композиция
С появлением java 8 была включена концепция функции и функции Bi, с помощью которых мы можем определять функции одного или двух входных параметров, например:
Functionpow = (n) -> n * n; assertThat(pow.apply(2)).isEqualTo(4); BiFunction multiply = (a, b) -> a * b; assertThat(multiply.apply(10, 5)).isEqualTo(50);
С помощью vavr мы можем иметь функции до 8 параметров с типами функций
Function1pow = (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 входных параметров, он также предлагает нам состав функций с операциями . .а Потом .применить и
Function1toUpper = 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");
Поднимание
При подъеме мы получаем возможность иметь дело с исключениями при составлении функций, с помощью которых функция будет возвращать опцию.нет в случае, если это исключение и опция.некоторые, в случае, если все прошло правильно.
Это очень полезно при создании функций, использующих сторонние библиотеки, которые могут возвращать исключения.
Function1toUpper = (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 всегда будет меньше, чем арность исходной функции, а возвращаемый результат будет исходной функцией арности – набор параметров
Function2cheers = (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 и скажи Привет применяя его частично, и у нас уже есть два более конкретных, чтобы поздороваться и мы могли бы получить больше примеров, если бы они нам понадобились.
Каррирование
Каррирование – это метод разложения функции из нескольких аргументов на последовательность функций аргумента.
Function3sum = (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, но в этом случае у нас будет исключение, которое было создано, чтобы иметь возможность его достичь или иметь возможность возвращать разные значения в зависимости от типа исключения.
Function2divide = (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 Listoriginal = 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”