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

Функциональное программирование на Java

Эта статья выведет вас на следующий уровень в java. Вы готовы? Вступление Этот… Помеченный java, функциональный.

Эта статья выведет вас на следующий уровень в java. Вы готовы?

Вступление

Эта статья в основном представляет собой набор примеров нескольких инструментов, предоставляемых Java 8. Эти инструменты помогли сделать программирование более простым и оптимальным (даже с точки зрения аппаратных ресурсов), используя декларативный подход. Следовательно, нам не нужно рассказывать много деталей, а только то, чего мы хотим достичь с помощью нашего кода. Я должен также подчеркнуть тот факт, что этот пакет инструментов – это то, что разработчик java “должен” знать.

Карта

1) Поток:

В этом разделе мы погрузимся в мир потоков. Мы поймем их, как они работают и зачем они нам нужны в первую очередь. 2) Ленивые выражения:

Узнав больше о ленивых выражениях, а именно о лямбдах и ссылках в этом разделе, вы сможете сделать свой код таким ленивым. Также сделает использование вашего оборудования оптимальным. 3) Функциональные интерфейсы:

На самом деле это основной раздел, в котором вы сможете увидеть реальный пример реализации кода и поймете, как использовать все, чему вы научились. Еще более конкретные примеры будут приведены в последнем разделе. 4) Необязательный:

Этот краткий раздел вернет вас к плохим воспоминаниям о ваших первых шагах по изучению java и точно к страшному NullPointerException . Но на этот раз вы сможете взять под контроль все, не беспокоясь о каких-либо непредсказуемых проблемах с нулевым значением.

Наконец, вы поработаете над реальными примерами и научитесь некоторым специфическим трюкам, которые изменят ваш стиль программирования к лучшему!

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

1) Java 8 Потоковый API

Поток Java 8 – это последовательность элементов из определенного источника, с которыми мы можем выполнять основные агрегатные операции. Этот источник может быть коллекцией, массивом или потоком – это называется конвейеризация . В отличие от коллекций, потоки не являются структурой данных. Они позволяют извлекать требуемое значение только тогда, когда оно нам нужно. Кроме того, они поддерживают отложенную оценку и изначально были созданы для использования с лямбдами (см. Вторую часть). Они содержатся в пакете java.util.stream. Существует очень большой набор операций для выполнения в потоке. Большинство из них возвращают поток, чтобы мы могли выполнять больше операций. Более того, потоки не хранят ни данные, ни изменения. Они просто выполняют внутреннюю итерацию один раз, а затем возвращают результат. Поэтому мы говорим, что они расходуемые и функциональные по своей природе . Еще одним важным моментом для потока является то, что они, возможно, неограниченны (неограниченны, поэтому нам не нужно указывать определенный размер потока). Таким образом, вы можете выполнять операции с первым и последним элементами потока, не беспокоясь о его размере или порядке элементов, поскольку они также сохраняют тот же порядок элементов, что и источник.

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

В двух словах:

в пакете java.util.stream в пакете java.util
только для обработки данных структура данных в памяти
разрешить операции только с требуемыми значениями (ленивый) все значения должны быть вычислены, а затем сохранены (нетерпеливо)
элементы потока посещаются только один раз в течение жизни потока (если вы хотите посетить их снова, используйте другой поток!) мы можем выполнять операции по сбору столько, сколько захотим
не нужен фиксированный размер. Тем не менее, мы можем получить первые/последние элементы должен иметь определенный размер

В следующем примере мы будем использовать следующий импорт:

импортируйте java.util. Список;

Если вы возьмете этот список друзей:

List friends = List.of("Mohamed","Abderrahmane","Ajar","Omar","Youssef");

Представьте, что мы хотим напечатать длину каждого имени. Обычно ваш код был бы примерно таким:

int[] r = new int[5];
for (int i = 0;i<5;i++) {
r[i] = friends.get(i).length();
System.out.println(r[i]);
}

Я думаю, что этот код вам понятен. Но другой способ сделать то же самое без необходимости объявлять какую-либо переменную заключается в следующем:

friends
   .stream()//create stream of friends
   .forEach(n->System.out.println( n.length()));//Then print successively each one of them

Пожалуйста, обратитесь к следующему разделу, чтобы понять, что это за выражения: t -> выражение .

2) Ленивые выражения

Ленивые выражения или ленивая оценка – это стратегия кодирования, а также образ мышления. Вы найдете множество сложных объяснений того, что такое ленивая оценка. Тем не менее, все дело в том, как сделать ваш код более ленивым , и под этим я подразумеваю оптимальный . Это можно сделать, отложив выполнение функции до тех пор, пока нам действительно не понадобится ее выполнение. Java ленив, когда дело доходит до оценки логических аргументов, например, в f1() f2() вызов f2() никогда не выполняется, если f1()

  • Ссылка на метод

Ссылка на метод относится к методу из класса или объекта, использующему класс::Имя метода синтаксис типа. В java 8 существуют различные типы доступных ссылок на методы. Например:

Класс::Имя статического метода Математика::макс эквивалентно математике.макс(x,y) Ссылка на статический метод
Экземпляр класса::Имя метода экземпляра System.out::println эквивалентно System.out.println(x) Ссылка на метод экземпляра из экземпляра
Класс::имя метода экземпляра Строка::длина, эквивалентная длине строки() Ссылка на метод экземпляра из типа класса
Класс::новый ArrayList::новый эквивалент нового ArrayList() Ссылка на конструктор
  • Лямбда-выражение

Лямбда-выражение также называют анонимной функцией, т. е. функцией без имени и какого-либо идентификатора. Это безымянные функции, заданные как постоянные значения и записанные точно в том месте, где это необходимо, обычно в качестве параметра какой-либо другой функции. Они пишут в такой форме: (параметры) -> выражение ; что означает, что выражение выполняется, когда оно вызывается, по значению, которое принимает переменные параметры . (Например, это выражение (x, y) -> x + y возвращает результат сложения x и y , также это выражение (x) ->System.out.println(x) выводит значение, присвоенное аргументу x ;

В приведенном выше примере .Для каждого(n->System.out.println (n.длина())); означает, что мы будем выполнять действие между скобками для каждого элемента нашего потока, а именно выводить их по одному.

Более того, приведенный выше код также может быть написан следующим образом с некоторыми небольшими изменениями:

friends
   .stream()
   .map(String::length)//Map each name to its length. As result we get a stream of lengths.
   .forEach(System.out::println);//Print each element of the stream.

3) Функциональные интерфейсы

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

  • В целом, функциональные интерфейсы – это интерфейсы, которые допускают внутри себя ровно один абстрактный метод в дополнение к любому количеству методов по умолчанию. Поскольку они не являются абстрактными, потому что у них есть реализация (я должен также подчеркнуть тот факт, что функции по умолчанию являются революционным дополнением в java 8). Функциональные интерфейсы также называются Интерфейсами единого абстрактного метода *(Интерфейсы SAM) *. В Java 8 функциональные интерфейсы также могут быть представлены с помощью лямбда-выражений, ссылок на методы и ссылок на конструкторы. Необязательно добавлять @FUNCTIONAL Interface аннотацию к функциональному интерфейсу, чтобы определить его. Например, у нас может быть что-то вроде этого:
@FunctionalInterface
public interface MyInterface 
{
public void job();//one abstract method
default void fct1(){//default method
//Method body
}
default void fct2(){//default method
//Method body
}

static void fct(){//default static method
//Method body
}
}
  • Методы по умолчанию являются смежной темой. Поскольку это методы, которые могут иметь реализацию в интерфейсе! Эта реализация по умолчанию может быть либо сохранена как есть, либо переопределена. Мы можем создать метод по умолчанию, добавив ключевое слово по умолчанию или, и это так здорово, сделав его статичным без необходимости добавлять значение по умолчанию ключевое слово. Я не буду вдаваться в подробности, которые вы можете найти позже (поверьте мне, эта новая функция потрясающая поэтому, пожалуйста, проверьте ссылки ), но хороший вопрос – что они также предоставляют, чтобы я поместил их в этот раздел? Ну, потому что методы по умолчанию включают функциональность lambdas в java. Взгляните на этот пример из java.lang. Повторяемый :
//This method allow you to perform action on collection
default void forEach(Consumer action) {
Objects.requireNonNull(action);
for (T t : this) {
action.accept(t);
}
}
/*
Before java 8 you have to iterate on your collection using the loop for. But now you can do something like this (I reused the first example here):
*/
friends
   .stream()
   .forEach(System.out::println);//to print all the friends names.
//Or;
friends
   .stream()
   .forEach(f -> System.out.println(f));
  • Кроме того, java.util имеет набор предварительно реализованных функциональных интерфейсов, таких как следующие примеры:
Представляет функцию, которая принимает один аргумент и выдает результат. Функция <Тип Ввода, Тип Возврата>
Представляет операцию, которая принимает один входной аргумент и не возвращает результата. Потребитель <Тип Ввода>
Представляет поставщика результатов. Поставщик <Тип Ввода>
Представляет предикат (логически значимую функцию) одного аргумента. Предикат <Тип Ввода>

Я просто приведу исчерпывающий пример реализации функции . Все остальное идет тем же путем. Тем не менее, если вам нужен полный список, вы можете проверить предоставленную документацию Oracle .

/*
This example represente a method that increment its int argument by one.
*/

//It would be something like this:
int increment(int i){
return i+1;
}

/*
With functional interface "Function" it becomes:
Don't forget to import:
import java.util.function.Function;
*/
Function increment = i -> ++i;

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

4) Необязательный

Когда я был “новичком” в java, я ненавидел это из-за одного страшного исключения, которое постоянно появляется на моем экране: Знаменитое java Исключение NullPointerException . Честно говоря, это было потому, что некоторые глупые, пропущенные, но необходимые начальные значения, так что java здесь не виновата. Позже я узнал об этом классе Необязательно пакета java.util . Необязательно, на самом деле это значение, которое может быть нулевым или не нулевым. У вас есть огромный набор инструментов и методов для манипулирования им. Если бы это было настоящее , если вы хотите выбросить конкретное исключение, если вы хотите получить значение, или еще у вас есть методы для этого в этом классе.

Итак, давайте сразу перейдем к некоторым примерам:

/*In all the example you can change the value 'null' and the SomeUserCostumizedOrAnyException by something else.
*/

/*
If you want to print a value when only it is present.
*/
System.out.println(Optional
   .ofNullable(null)
   .orElseGet(() -> "value to show by default"));
/*
If you want to print a value when only it is present, or just throw an exception.
*/

// method reference
System.out.println(Optional.ofNullable(null).orElseThrow(SomeUserCostumizedOrAnyException::new));

//Lambda
System.out.println(Optional.ofNullable(null)
   .orElseThrow(()-> new SomeUserCostumizedOrAnyException("the default value is missed")));
/*
If you want to check of the value is present and then print the String email(you have first change null by something like this "xyz@example.com")
*/

Optional.ofNullable(null).ifPresentOrElse(v->
System.out.println("Sending email to "+v+"."),
() -> System.out.println("Cannot send emails!")
);
/*
A last comparison, in case of you want to just get the value.
*/

//normal method(imperative approach in which you declare all your variables and explicitly the logic of how to get the wanted result)
String s="present value";
if(s==null){
System.out.println("s is null");
} else {
System.out.println(s);
}

//new method with Optional (declarative approach in which you just describe what you want as result exactly)
System.out.println(Optional.ofNullable("present value").orElse("s is null"));

//Or just simply
System.out.println(Optional.of("present value").get());

Вывод

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

В этой статье вы узнали:

Потоки Потоки делают ваш код ленивым, используя только требуемые значения в источнике данных. Для этого у вас есть мощный набор методов агрегирования, которые вы можете использовать
Ленивые выражения Лямбды и ссылка на метод изменяют ваш стиль кодирования, чтобы он был более декларативным, а также более ленивым
Функциональные Интерфейсы Эта часть служит теорией функционального программирования на java и некоторыми хорошими примерами для ее понимания.
Необязательный Этот класс много работает с потоками и функциональными интерфейсами, в случае нулевых значений. Это позволит вам избежать борьбы с исключением NullPointerException при каждом выполнении кода.

Спасибо вам за чтение.

Рекомендации

кактодоинджава

Документация Oracle:

Функция

Течение

Оригинал: “https://dev.to/abdorah/java-functional-programming-57gd”