Функциональное программирование в Java
Тем, кто знаком с функциональным программированием, но никогда не применял его в Java, думаю, это будет тоже интересно.
Вводим конструкцию «функция» в языке Java
Что такое функциональное программирование? Если в двух словах, то функциональное программирование — это программирование, в котором функции являются объектами, и их можно присваивать переменным, передавать в качестве аргументов другим функциям, возвращать в качестве результата от функций и т. п. Преимущества, которые раскрывает такая возможность, будут понятны чуть позже. Пока нам надо разобраться, как в Java можно использовать саму конструкцию «функция».
Как известно, в Java нету функций, там есть только классы, методы и объекты классов. Зато в Java есть анонимные классы, то есть классы без имени, которые можно объявлять прямо в коде любого метода. Этим мы и воспользуемся. Для начала объявим такой интерфейс:
Теперь в коде какого-нибудь метода мы можем объявить анонимную реализацию этого интерфейса:
Такую реализацию мы и будем называть «анонимной функцией». С точки зрения функционального программирования с ней можно делать все то же самое, что и с функцией из функциональных языков: присваивать переменным, передавать в качестве аргумента другим функциям(и методам классов), получать в качестве результата от функций(и методов классов).
Теперь можно перейти к изложению некоторых базовых паттернов функционального программирования.
Работа с коллекциями в функциональном стиле
Допустим, у нас есть некая коллекция целых чисел. Мы хотим их вывести на экран в виде строки, и каждое число в строке будет разделено через запятую. Нефункциональное решение выглядело бы примерно так:
Для реализации функционального решения нам потребуется сперва подготовить несколько функций и методов. Будем объявлять их в качестве статических полей класса:
Теперь наш метод joinNumbers будет выглядить следующим образом:
Метод реализован ровно в одну простую строку.
Работа с коллекциями с помощью Google Collections
В Google Collections конечно есть еще много других полезных вещей как для функционального программирования, так и для работы с коллекциями в императивном стиле.
Ссылки
Руководство разработчика Java по Функциям Azure
В данном руководстве содержатся подробные сведения, полезные для разработчиков функций Azure с помощью Java.
Разработчикам Java, незнакомым с функциями Azure, рекомендуются следующие статьи.
Основные сведения о функции Java
Модель программирования
Понятия триггеров и привязок играют решающую роль в Функциях Azure. Триггеры запускают выполнение вашего кода. Привязки предоставляют возможность передавать данные, а также возвращать их из функции без необходимости написания кода доступа к ним.
Создание функций на Java
Чтобы упростить создание функций на Java, созданы специальные средства и архетипы на основе Maven, которые предоставляют готовые шаблоны Java для создания проектов с определенным триггером функции.
Инструментарий на основе Maven
В следующих средах разработки есть инструментарий Функций Azure, который позволяет создавать проекты для функций Java:
В статьях, доступных по предложенным выше ссылкам, демонстрируется создание простых функций в удобной для вас интегрированной среде разработки.
Формирование шаблонов для проекта
Следующая команда создает новый проект функции Java на основе этого архетипа:
Чтобы приступить к использованию архетипа, воспользуйтесь кратким руководством по Java.
Структура папок
Ниже приведена структура папок в проекте Функций Azure на Java:
Вы можете использовать общий файл host.json для настройки приложения-функции. У каждой функции есть собственный файл кода (.java) и файл конфигурации привязки (function.json).
Вы можете добавить несколько функций в проект. Не добавляйте функции в отдельные JAR-файлы. Именно FunctionApp из целевого каталога будет развернут в виде приложения-функции в Azure.
Триггеры и заметки
Функции вызываются триггером, таким как HTTP-запрос, таймер или обновление данных. Функция должна обработать такой триггер и связанные с ним входные данные, а также создать на их основе одно или несколько выходных значений.
Используйте заметки Java, включенные в пакет com.microsoft.azure.functions.annotation.*, чтобы привязать входные и выходные данные к своим методам. Дополнительные сведения см. в справочной документации по Java.
Чтобы локально обрабатывать триггеры хранилища BLOB-объектов, очередей или таблиц Azure, необходимо указать учетную запись хранения Azure в файле local.settings.json.
Ниже приведена созданная соответствующая function.json function.json :
Версии Java
Версия Java, используемая при создании приложения-функции, имеющей функции, выполняющиеся в Azure, указывается в файле pom.xml. В настоящее время архетип Maven создает файл pom.xml для Java 8, который можно изменить перед публикацией. Версия Java, указанная в файле pom.xml, должна совпадать с версией, на которой локально разрабатывается и тестируется приложение.
Поддерживаемые версии
В следующей таблице приведены текущие поддерживаемые версии Java для каждой основной версии среды выполнения функций по операционным системам.
Версия службы «Функции» | Версии Java (Windows) | Версии Java (Linux) |
---|---|---|
4.x | 11 8 | 11 8 |
3.x | 11 8 | 11 8 |
2.x | 8 | Недоступно |
Если для развертывания не указана версия Java, по умолчанию во время развертывания в Azure архетипом Maven используется версия Java 8.
Определение версии развертывания
Архетип Maven создает файл pom.xml для заданной версии Java. Следующие элементы файла pom.xml указывают версию Java, необходимую для использования.
Элемент | Значение Java 8 | Значение Java 11 | Описание |
---|---|---|---|
Java.version | 1.8 | 11 | Версия Java для модуля компилятора Maven. |
JavaVersion | 8 | 11 | Версия Java, размещенная в Azure приложением-функцией. |
На следующих примерах показаны параметры для Java 8, расположенные в соответствующих разделах файла pom.xml.
Java.version
JavaVersion
Определение операционной системы, используемой для развертывания
Maven также позволяет задать операционную систему, в которой выполняется приложение-функция в Azure. Используйте элемент os для выбора операционной системы.
Элемент | Windows | Linux | Docker |
---|---|---|---|
os | windows | linux | docker |
На следующем примере показан параметр операционной системы в разделе runtime файла pom.xml:
Обеспечения доступности и предоставления поддержки времени выполнения пакета JDK
Для локальной разработки приложений-функций Java используйте пакет Java JDK Azul Zulu Enterprise for Azure, который можно скачать в Azul Systems. Функции Azure используют среду выполнения Azul Java JDK при развертывании приложения-функции в облако.
Поддержка Azure для устранения проблем с пакетами JDK и приложениями-функциями предоставляется, если у вас есть соответствующий план поддержки.
Настройка виртуальной машины Java
Функции Azure позволяют настраивать виртуальную машину Java, которая используется для выполнения функций Java. По умолчанию применяются следующие параметры виртуальной машины Java.
В план потребления необходимо также добавить параметр WEBSITE_USE_PLACEHOLDER со значением 0, чтобы работала эта настройка. Но этот параметр увеличивает время холодного запуска для функций Java.
Портал Azure
Azure CLI
В этом примере показано, как включить режим без монитора. Замените в нем заполнитель именем приложения-функции, а — именем группы ресурсов.
Сторонние библиотеки
Поддержка типов данных
Для входных и выходных привязок можно использовать объекты POJO, определенные в azure-functions-java-library типы, или примитивные типы данных, как например String или Integer.
Объекты POJO
Двоичные данные
Привязки
Входные и выходные привязки реализуют декларативный способ подключения к данным из кода. У функции может быть несколько входных и выходных привязок.
Пример привязки входа
Эта функция вызывается с помощью HTTP-запроса.
Пример выходной привязки
При наличии нескольких выходных привязок используйте возвращаемое значение только для одной из них.
Эта функция вызывается через HttpRequest. Она записывает несколько значений в Хранилище очередей.
HttpRequestMessage и HttpResponseMessage
Специализированные типы | Назначение | Типичное применение |
---|---|---|
HttpRequestMessage | Триггер HTTP | Получение метода, заголовков или запросов |
HttpResponseMessage | Привязка к выходным данным HTTP | Возврат кодов состояния, отличных от 200 |
Метаданные
Несколько триггеров отправляют метаданные триггеров вместе с входными данными. Вы можете использовать аннотацию @BindingName для привязки к метаданным триггера.
Предоставленное в заметке имя должно соответствовать свойству метаданных.
Контекст выполнения
Средство ведения журнала
Просмотр журналов и трассировки
Вы можете использовать интерфейс Azure CLI для потоковой передачи журналов со стандартными данными и журналов ошибок в формате Java, а также ведения других журналов приложений.
Ниже показано, как настроить для приложения-функции запись журнала приложения с использованием Azure CLI.
Чтобы выполнять потоковую передачу выходных данных журналов для приложения-функции через Azure CLI, откройте новое окно командной строки, сеанс Bash или терминала и введите следующую команду:
Команда AZ webapp log хвоста имеет параметры для фильтрации выходных данных с помощью параметра.
Чтобы скачать файлы журналов как единый ZIP-файл с помощью Azure CLI, откройте командную строку, Bash или сеанс терминала и введите следующую команду:
Перед выполнением этой команды необходимо включить ведение журнала файловой системы с помощью портала Azure или Azure CLI.
Переменные среды
В следующем примере возвращается параметр приложенияс ключом с именем :
Значение параметра приложения FUNCTIONS_EXTENSION_VERSION должно быть
3, чтобы оптимизировать процесс холодного запуска.
Дальнейшие действия
Дополнительные сведения о разработке в службе «Функции Azure» на Java см. в следующих статьях.
Создание своих функций, передача параметров
1. Функции/Методы в Java
Вы уже выучили большое количество команд в Java, и это значит, что вы можете писать достаточно сложные программы. 10, 20, 30 строк кода в программе — не такая и большая программа, верно?
А вот программа в 100+ строк — уже большая, и разбираться в ее коде довольно сложно. Можно ли как-то упростить написание и чтение программ с большим количеством кода?
Да, и помогут нам в этом методы (функции).
Без метода | С методом |
---|
Любой код можно разбить на отдельные методы. Это делают для упрощения: считается, что лучше иметь много маленьких методов, чем один большой. Скоро вы будете удивляться тому, что раньше писали свои программы, но не писали свои методы.
2. Объявление метода в Java
Так как все-таки правильно написать свой метод?
При объявлении (создании) метода нужно учитывать много нюансов, но давайте начнем с основного. Как нам все-таки объявить самый простой метод? Объявление простого метода выглядит так:
После того, как мы создали метод, мы можем вызывать его в других наших методах. Вызов выглядит так:
Где имя — это уникальное имя метода, который мы хотим вызвать, и команды которого мы хотим выполнить в месте его вызова.
Когда программа дойдет до команды, содержащей вызов нашего метода, она просто перейдет в метод, выполнит все его команды, вернется в изначальный метод и продолжит выполнение.
Код метода может содержать вызовы других методов:
Вызываем метод printWiFi10Times()
Объявляем метод printWiFi10Times
Вызываем метод printWiFi() 10 раз в цикле
Объявляем метод printWiFi
Выводим на экран текст:
3. Факты о методах
Вот еще несколько фактов о методах:
Факт 1. Метод — это всегда часть класса.
Метод можно объявить только в классе. Метод нельзя объявить внутри другого метода. Метод нельзя объявить вовне класса.
Факт 2. Имя метода не несет сакрального смысла
Неважно, как называются методы — это ни на что не влияет. Метод main — это такой же метод, как и все остальные. Просто такое имя выбрали для метода, с которого Java-машина начинает исполнение программы. Ничего волшебного в нем нет.
Факт 3. Порядок методов в классе не важен
Вы можете написать ваши методы в классе в любом порядке — это никак не повлияет на выполнение программы. Пример:
Факт 4. Переменные внутри одного метода никак не связаны с переменными других методов
Что происходит в Вегасе, остается в Вегасе. А переменные, объявленные внутри метода, остаются внутри этого метода.
В двух соседних методах могут быть объявлены одинаковые переменные, и эти переменные никак не связаны друг с другом.
4. Имена методов
Уже давно известно, что в программировании две самые сложные проблемы — как правильно подобрать название метода и как назвать переменную.
На самом деле, уже существует чуть ли не целая наука о том, как правильно называть методы. И у каждого языка программирования есть свои стандарты. В Java принято руководствоваться такими принципами:
Принцип 1. Имя метода должно кратко описывать то, что этот метод делает.
Тогда программист, который читает ваш код, по имени метода сможет догадаться, что этот код делает, и ему не нужно будет каждый раз смотреть код вызываемых методов. Да и назначение методов запомнить легче.
Вспомните тот же Thread. sleep () — «усыпить программу» и Scanner. nextInt () — «считать следующее целое число». Удобно же, правда.
Принцип 2. Имя метода может состоять из нескольких слов.
Однако для этого случая есть несколько ограничений:
Такой стандарт написания имен называется CamelCase (Camel — верблюд. Большие буквы похожи на верблюжьи горбы).
Принцип 3. Имя метода начинается с глагола.
Метод всегда что-то делает, поэтому первое слово в названии метода — это всегда действие.
Принцип 4. Используйте только латинские буквы и цифры
Java очень хорошо поддерживает разные языки. Вы можете написать имена переменных, методов и классов хоть на русском, хоть на китайском — все будет работать!
Но! Как долго вы бы учили Java, если бы названия метода System.out.println() было на китайском? Гораздо дольше, чем сейчас, не так ли? Это, во-первых.
Во-вторых, над многими проектами работают интернациональные команды. Очень большое количество Java-библиотек используется программистами со всего мира.
Поэтому рекомендуется в именах методов использовать только латинские буквы и цифры.
Пользовательские функции Java: как создать функцию в Java?
Функция представляет собой небольшую программу, выполняющую определённые действия, когда её (функцию) вызывают по имени. В языке программирования Java есть много встроенных и готовых к работе функций, однако никто не мешает создавать пользователю свои функции.
Исходя из вышеизложенного, пользовательской функцией можно назвать функцию, которую создал сам разработчик для решения конкретной задачи. Непосредственный процесс написания функций считается процедурным подходом в программировании.
Что обычно помещают в функции? Как правило, речь идёт о повторяющемся программном коде. Соответственно, чтобы программисту не писать те же самые строчки кода снова и снова, он просто выносит эти строчки в отдельный блок, а потом вызывает этот блок в основном Java-коде программы тогда, когда это нужно.
Идём дальше, в Java выделяют 2 вида функций: 1. Функция, которая что-либо возвращает. 2. Функция, которая не возвращает ничего.
Вдобавок к этому, функция в Джаве может быть с параметрами и без них. Тут следует напомнить важный момент: переменная, которая создана в функции, после завершения этой функции «умирает», то есть больше не существует.
Рассмотрим формулу создания функции в Java:
Создание функций в Java
Для начала создадим пользовательскую функцию, которая что-нибудь возвращает. Этот тип функций используется чаще всего, ведь очень часто нужно что-либо посчитать, выполнить преобразование и т. п., то есть речь идёт о том, чтобы использовать полученный результат вне этой функции. А так как всё, что создано в функции, после её завершения «погибает», нам надо, чтобы в основной код программы вернулся результат работы этой функции. Для это используется оператор return.
Итак, создадим пользовательскую функцию, которая вернёт нам значение переменной, а также присвоит это значение переменной в основном коде.
Таким образом, создаётся переменная, которая потом возвращается в нужном разработчику месте. Но вообще, в теле пользовательской функции мы можем прописать любой код, например, по созданию массивов, циклов и другой структуры.
Теперь давайте создадим функцию в Java, которая ничего возвращать не будет. Такой тип функции может пригодиться во время работы с глобальными переменными либо если надо что-либо напечатать и вывести на экран.
По большему счёту, особых отличий между написанием функций обоих видов нет. Главное — указать другой тип (void) и не применять return.
Вызываем функции без параметров
Чтобы работать с функциями, получая от них какой-либо результат, надо вызвать функцию в нужном месте по имени.
Давайте воспользуемся написанными нами функциями и вызовем их в основном коде.
Вывод будет следующим:
Следует добавить, что функция, которая что-либо возвращает, обязательно должна вызываться так, как указано в примере, то есть возвращаемое значение должно быть чему-то присвоено.
Создаём функции с параметрами
Иногда надо произвести над значениями какие-нибудь действия. Для этого нужно передать нашей пользовательской функции эти самые значения. Когда значения передаются в нашу функцию, они становятся её аргументами функции.
Итак, давайте создадим функцию с параметрами, а потом вызовем её в основном коде с помощью аргументов. Возведём переменную в определённую степень, а потом вернём значение в переменную.
Необходимые параметры нужно указывать при создании функции (речь идёт о переменных в скобках после имени функции). При этом аргументы надо передать в обязательном порядке, иначе функция попросту не заработает, ведь у неё просто не будет значения, с которым надо взаимодействовать. Аргументы надо указывать при вызове функции (2 целочисленных значения).
В консоли увидим следующее значение:
Таким образом, в функцию в Java мы можем помещать, что угодно. В нашем же случае, аргументы надо передать обязательно, иначе возникнет ошибка.
Вот и всё, надеемся, что теперь вы разобрались с темой по созданию пользовательских функций на языке Java. Если же интересуют более сложные задачи, добро пожаловать на наш курс для опытных Java-разработчиков!
Функции Java 8 с примерами
Функции Java 8 с примерами. Функции Java 1.8. Новые функции Java 8 с примерами методов forEach, по умолчанию и статических методов, лямбда-выражений, потока и т.д.
Java 8 была выпущена 18 марта 2014 года. Это было давно, но до сих пор многие проекты выполняются на Java 8. Это потому, что это был крупный релиз с большим количеством новых функций. Давайте рассмотрим все интересные и основные функции Java 8 на примере кода.
Краткий обзор функций Java 8
Некоторые из важных функций Java 8 являются;
Давайте кратко рассмотрим эти функции Java 8. Я приведу некоторые фрагменты кода для лучшего понимания функций простым способом.
1. Метод forEach() в итерационном интерфейсе
Всякий раз, когда нам нужно пройти через коллекцию, нам нужно создать итератор, вся цель которого состоит в повторении, а затем у нас есть бизнес-логика в цикле для каждого из элементов Коллекции. Мы можем получить исключение ConcurrentModificationException, если итератор используется неправильно.
Java 8 представила для каждого метода в java.lang.Итерируемый интерфейс, так что при написании кода мы фокусируемся на бизнес-логике. Метод forEach использует функцию java.util..Объект потребителя в качестве аргумента, поэтому он помогает разместить нашу бизнес-логику в отдельном месте, которое мы можем повторно использовать. Давайте рассмотрим каждое использование на простом примере.
Количество строк может увеличиться, но для каждого метода помогает наличие логики итерации и бизнес-логики в отдельном месте, что приводит к более высокому разделению проблем и более чистому коду.
2. стандартные и статические методы в интерфейсах
Если вы внимательно прочтете сведения о каждом методе, вы заметите, что он определен в итерационном интерфейсе, но мы знаем, что интерфейсы не могут иметь тело метода. Начиная с Java 8, интерфейсы расширены, чтобы иметь метод с реализацией. Мы можем использовать по умолчанию и статическое ключевое слово для создания интерфейсов с реализацией метода. для каждой реализации метода в итерационном интерфейсе:
Решение заключается в том, что компилятор создаст исключение в этом сценарии, и нам придется предоставить логику реализации в классе, реализующем интерфейсы.
Обратите внимание, что оба интерфейса имеют общий метод log() с логикой реализации.
Как вы можете видеть, Интерфейс 1 имеет реализацию статического метода, которая используется в Мой класс.long() реализация метода. Java 8 использует по умолчанию и статические методы в значительной степени в API сбора и методы по умолчанию добавляются, чтобы наш код оставался обратно совместимым.
Если какой-либо класс в иерархии имеет метод с такой же сигнатурой, то методы по умолчанию становятся неактуальными. Объект является базовым классом, поэтому, если у нас есть методы по умолчанию equals (), hashCode() в интерфейсе, это станет неуместным. Вот почему для большей ясности интерфейсам не разрешается использовать методы по умолчанию для объектов.
3. Функциональные интерфейсы и лямбда-выражения
Если вы заметили приведенный выше код интерфейса, вы заметите аннотацию @functional Interface. Функциональные интерфейсы-это новая концепция, представленная в Java 8. Интерфейс с ровно одним абстрактным методом становится Функциональным интерфейсом. Нам не нужно использовать аннотацию @Functional Interface для обозначения интерфейса как функционального интерфейса.
Аннотация @Functional Interface-это средство, позволяющее избежать случайного добавления абстрактных методов в функциональные интерфейсы. Вы можете думать об этом так @Переопределите аннотацию, и лучше всего ее использовать. ява.ланг.Запускаемый с помощью одного абстрактного метода run() является отличным примером функционального интерфейса.
Одним из основных преимуществ функционального интерфейса является возможность использовать лямбда-выражения для их создания. Мы можем создать экземпляр интерфейса с анонимным классом, но код выглядит громоздким.
Поскольку функциональные интерфейсы имеют только один метод, лямбда-выражения могут легко обеспечить реализацию метода. Нам просто нужно предоставить аргументы метода и бизнес-логику. Например, мы можем написать вышеописанную реализацию, используя лямбда-выражение как:
Если у вас есть один оператор в реализации метода, нам также не нужны фигурные скобки. Например, приведенный выше интерфейс 1 анонимный класс может быть создан с помощью лямбда-кода следующим образом:
Таким образом, лямбда-выражения являются средством для легкого создания анонимных классов функциональных интерфейсов. Использование лямбда-выражений не дает никаких преимуществ во время выполнения, поэтому я буду использовать их осторожно, потому что я не против написать несколько дополнительных строк кода.
Новый пакет java.util.function был добавлен с набором функциональных интерфейсов для предоставления целевых типов для лямбда-выражений и ссылок на методы. Лямбда-выражения-огромная тема, об этом я напишу отдельную статью в будущем.
4. Java Stream API для массовых операций с данными в коллекциях
В Java 8 добавлен новый java.util.stream для выполнения операций фильтрации/сопоставления/уменьшения подобных с коллекцией. Потоковый API позволит выполнять как последовательное, так и параллельное выполнение. Это одна из лучших функций для меня, потому что я много работаю с коллекциями и, как правило, с большими данными, нам нужно отфильтровать их в зависимости от некоторых условий.
Интерфейс сбора данных был расширен с помощью методов stream() и parallelStream() по умолчанию для получения потока для последовательного и параллельного выполнения. Давайте рассмотрим их использование на простом примере.
Если вы запустите приведенный выше пример кода, вы получите такой вывод:
Обратите внимание, что значения параллельной обработки не в порядке, поэтому параллельная обработка будет очень полезна при работе с огромными коллекциями.
5. API времени Java
Просто взглянув на пакеты API Java Time, я чувствую, что они будут очень просты в использовании. В нем есть некоторые подпакеты java.time.format, которые предоставляют классы для печати и анализа дат и времени, а java.time.zone обеспечивает поддержку часовых поясов и их правил.
6. Улучшения API сбора данных
Мы уже видели для каждого метода() и API потока для коллекций. Некоторые новые методы, добавленные в API сбора, включают:
7. Улучшения API параллелизма
Некоторые важные параллельные усовершенствования API включают:
8. Улучшения ввода-вывода Java
Некоторые улучшения ввода-вывода, известные мне, заключаются в следующем:
Различные улучшения Java 8 Core API
Некоторые другие улучшения API, которые могут пригодиться, включают:
Это все для функций Java 8 с примерами программ. Если я пропустил некоторые важные функции Java 8, пожалуйста, дайте мне знать в комментариях.