Анонимные функции java кратко

Обновлено: 04.07.2024

В этой статье мы расскажем о всеобъемлющем руководстве по лямбда-выражениям на Java.

1. Лямбда-выражения Java-учебник — Введение

Лямбда-выражения считаются одной из лучших функций, представленных в Java 8. Лямбда-выражения рассматриваются как первый шаг Java в мир функционального программирования . Это можно рассматривать как функцию, которая может быть создана без класса. Он также может быть передан как параметр и может быть выполнен, когда и при необходимости. Лямбда-выражения Java — это краткое представление анонимных функций, которые можно передавать. Анонимные классы с одной функцией представили громоздкую презентацию с дополнительным синтаксисом. Эти выражения направлены на то, чтобы устранить эту путаницу.

Как мы уже говорили выше, лямбда-выражения Java являются безымянными функциями, которые можно передавать как постоянные значения. Это означает, что они могут присутствовать в любом месте, где могло присутствовать любое другое постоянное значение, но обычно записываются в качестве параметра в какую-либо другую функцию. Чтобы рассмотреть канонический пример, мы можем передать функцию сравнения в общую функцию сортировки , и вместо того, чтобы пытаться определить целую процедуру (и вызвать лексический разрыв и загрязнение пространства имен), чтобы описать это сравнение, мы можем просто передать Лямбда-выражение, описывающее сравнение. Давайте посмотрим на некоторые свойства лямбда-выражения:

  • Аноним: его все еще можно назвать анонимным, потому что у него нет явного имени.
  • Кратко: как уже упоминалось в случае с анонимными классами, мы пишем намного меньше кода на Lambdas по сравнению с анонимными классами.
  • Функция: лямбда больше похожа на функцию, чем на метод. Это потому, что метод принадлежит классу, а лямбда — нет. Но, как и метод, лямбда принимает список параметров, имеет тело и может также генерировать исключения.
  • Может передаваться: лямбда может передаваться другим функциям, как обычный параметр.

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

2. Написание лямбда-выражений

В этом разделе мы увидим, как лямбда-выражения Java могут сократить количество строк кода, которые необходимо написать для выполнения некоторых простых операций. Например, мы сравним количество строк кода, чтобы создать функцию Comparator. Чтобы провести сравнение, мы POJO простой класс POJO класс Student который содержит идентификатор Student в качестве Long и имя в качестве параметра String :

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

Теперь ошибки синтаксиса возникать не будет. Мало того, мы теперь можем даже вызвать эту функцию через переменную anonym:

Этот же синтаксис прекрасно сработает и с именованной функцией, например, так:

Правда, если мы попробуем вызвать функцию по ее второму имени:

то возникнет ошибка, что func не определена. Дело в том, что по приоритетам в глобальной области видимости (то есть, вне функции) будет существовать только переменная anonym, но не переменная func. Имя func существует только внутри самой функции, за ее пределами такого имени уже нет.

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

Обратите внимание, чтобы этот код сработал, после директивы “use strict” нужно поставить точку с запятой. Без точки с запятой интерпретатор будет полагать, что мы прописываем аргумент у строки “use strict” и получим синтаксическую ошибку.

Теперь наша функция вызывается непосредственно в том месте, где объявлена. Это называется функциональным выражением. То есть, когда интерпретатор встречает такую запись, он немедленно выполняет код, находящийся внутри анонимной функции. Функция вызывается благодаря круглым скобкам, записанным после ее объявления. Как пример, такие функции часто используют как аргументы callback-функций, о которых мы немного говорили на прошлом занятии. Приведу здесь еще один пример. Вызовем анонимную функцию через секунду после запуска скрипта. Это делается с помощью стандартной JavaScript-функции setTimeout:

Здесь первый агрумент – это callback-функция, а второй – задержка исполнения в миллисекундах (1000 мс = 1 сек).

Стрелочные функции

В новой спецификации стандарта языка JavaScript – ES6 вводится понятие стрелочных функций. Это такое развитие или, скорее, упрощение анонимных функций. Что это такое? Представим, что у нас вот такая анонимная функция:

Преобразуем ее в стрелочную. Уберем ключевое слово function, а вместо фигурных скобок запишем вот такие символы => - очень похоже на стрелку.

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

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

Но особенности стрелочных функций на этом не заканчиваются. Предположим, мы хотим, чтобы такая функция возвращала какой-либо результат. В обычных функциях для этого используется оператор return. Здесь это делается несколько иначе. Давайте возвратим стрелочной функцией строку, которая выводилась в консоль. Для этого ее нужно записать так:

Смотрите как элегантно это выглядит. Если мы хотим что-то вернуть, то просто пишем возвращаемое выражение после стрелки. И никакого оператора return! Мало того, его здесь даже нельзя прописать – будет синтаксическая ошибка. Это все работает только в таком виде. То есть, когда телом стрелочной функции выступает какое-либо одно выражение (в данном случае – это строковый литерал), то записывая его без фигурных скобок, оператор return подразумевается.

Как пример можно записать и такое выражение:

Увидим в консоле результат суммы – число 78. И так далее. Но, если мы поместим тело функции в фигурные скобки, то возврат уже работать не будет:

Мы получим значение undefined, как правило, означающее, что функция ничего не возвращает. Чтобы все работало, оператор return здесь обязателен:

Фигурные скобки в стрелочных функциях используются, если тело функции содержит более одного выражения:

Здесь фигурные скобки обязательны и без них код работать уже не будет.

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

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

Во всех других случаях круглые скобки обязательны:

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

Видео по теме























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

однако, вы можете реализовать интерфейс с функцией так :

и вы можете использовать это с внутренними классами, чтобы получить почти анонимную функцию :)

вот пример анонимного внутреннего класса.

это не очень полезно, но показывает, как создать экземпляр анонимного внутреннего класса, который extends Object и @Override его toString() метод.

см. также

вот пример того, как вы можете сортировать String[] на основе String.length() .

обратите внимание на трюк сравнения по вычитанию, используемый здесь. Следует сказать, что этот метод Вообще нарушен: он применим только тогда, когда вы можете гарантировать, что он не переполнится (так обстоит дело с String длины.)

см. также

  • Java Integer: что такое более быстрое сравнение или вычитание?
    • сравнение-по-вычитание сломанные в общем

    С введением лямбда-выражения в Java 8 Теперь вы можете иметь анонимных методов.

    скажем у меня есть класс Alpha и я хочу, чтобы фильтр Alpha s при определенном условии. Для этого вы можете использовать Predicate . Это функциональный интерфейс, который имеет метод test принимает Alpha и возвращает boolean .

    предполагая, что метод фильтра имеет эту подпись:

    со старым анонимным решением класса вам нужно будет что-то вроде:

    С помощью Java 8 lambdas вы можете сделать:

    для получения более подробной информации см. лямбда-выражения руководство

    анонимные внутренние классы, реализующие или расширяющие интерфейс существующего типа, были сделаны в других ответах, хотя стоит отметить, что могут быть реализованы несколько методов (часто с событиями JavaBean-style, например).

    небольшая признанная особенность заключается в том, что, хотя анонимные внутренние классы не имеют имени, у них есть тип. В интерфейс можно добавить новые методы. Эти методы могут применяться только в ограниченных случаях. Главным образом прямо на new само выражение и внутри класса (включая инициализаторы экземпляра). Это может смутить новичков, но это может быть "интересно" для рекурсии.

    (Я написал это с помощью node , а не cur на print метод. сказать " нет "захвату" неявно final " местные жители?)

    Да, если вы используете последнюю версию Java версии 8. Java8 позволяет определить анонимные функции, которые были невозможны в предыдущих версиях.

    возьмем пример из java docs, чтобы узнать как мы можем объявлять анонимные функции, классы

    следующий пример, HelloWorldAnonymousClasses, использует анонимный классы в операторах инициализации локальных переменных frenchGreeting и spanishGreeting, но использует местный класс инициализация переменной englishGreeting:

    синтаксис анонимных классов

    рассмотрим экземпляр объекта frenchGreeting:

    анонимное выражение класса состоит из следующего:

    имя интерфейса для реализации или класса для расширения. В этом например, анонимный класс реализация интерфейса Адский мир.

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

    тело, которое является телом объявления класса. Более конкретно, в объявления body, method разрешены, но операторы не.

    Введение

    В этой статье, с помощью примеров, мы изучим lambda-выражения в Java, их использование с функциональными интерфейсами, параметризированными функциональными интерфейсами и Stream API.

    Лямбда выражения были добавлены в Java 8. Их основная цель – повысить читабельность и уменьшить количество кода.

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

    Что же такое функциональный интерфейс?

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

    Например, интерфейс Runnable из пакета java.lang является функциональным, потому, что он содержит только один метод run().

    Пример 1: объявление функционального интерфейса в java


    В приведенном выше примере, интерфейс MyInterface имеет только один абстрактный метод getValue(). Значит, этот интерфейс — функциональный.

    Здесь мы использовали аннотацию FunctionalInterface, которая помогает понять компилятору, что интерфейс функциональный. Следовательно, не позволяет иметь более одного абстрактного метода. Тем не менее, мы можем её опустить.

    В Java 7, функциональные интерфейсы рассматривались как Single Abstract Methods (SAM). SAM обычно реализовывались с помощью анонимных классов.

    Пример 2: реализация SAM с помощью анонимного класса в java


    Результат выполнения:


    В этом примере, мы принимаем анонимный класс для вызова метода. Это помогало писать программы с меньшим количеством строк кода в Java 7. Однако, синтаксис оставался достаточно сложным и громоздким.

    Java 8 расширила возможности SAM, сделав шаг вперед. Как мы знаем, функциональный интерфейс содержит только один метод, следовательно, нам не нужно указывать название метода при передаче его в качестве аргумента. Именно это и позволяет нам lambda-выражения.

    Введение в лямбда-выражения

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

    Как записать лямбда-выражение в Java?

    В Java, лямбда-выражения имеют следующий синтаксис:


    Здесь мы использовали новый оператор (->) — лямбда-оператор. Возможно, синтаксис кажется немного сложным. Давайте разберем пару примеров.

    Предположим, у нас есть такой метод:


    Мы можем записать его, используя лямбда, как:


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

    Типы лямбда-выражений

    В Java, тело лямбды может быть двух типов.

    1. Однострочные


    2. Блочные (многострочные)


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

    Примечание: многострочные лямбда-выражения, всегда должны иметь оператор return, в отличии от однострочных.

    Пример 3: лямбда-выражение

    Давайте напишем Java программу, которая бы возвращала значение Pi, используя лямбда-выражение.

    Как говорилось ранее, лямбда-выражение не выполняется само собой. Скорее, оно формирует реализацию абстрактного метода, объявленного в функциональном интерфейсе.

    И так, для начала, нам необходимо описать функциональный интерфейс.

    • Мы создали функциональный интерфейс MyInterface, который содержит один абстрактный метод getPiValue().
    • Внутри класса Main, мы объявили ссылку на MyInterface. Обратите внимание, что мы можем объявить ссылку на интерфейс, но не можем создать его объект.


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

    Пример 4: использование лямбда-выражения с параметрами


    Результат выполнения:

    Параметризированный функциональный интерфейс

    До этого момента, мы использовали функциональные интерфейсы, которые принимали только один тип значения. Например:


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

    Пример 5: параметризированный интерфейс и лямбда-выражения


    В этом примере, мы создали параметризированный функциональный интерфейс GenericInterface, который содержит параметризированный метод func().

    Затем, внутри класса Main:

    • GenericInterface reverse – создает ссылку на интерфейс, который работает со String.
    • GenericInterface factorial — создает ссылку на интерфейс, который работает с Integer.

    Лямбда-выражения и Stream API

    В JDK8 добавлен новый пакет java.util.stream, который позволяет java-разработчикам выполнять такие операции, как поиск, фильтрация, сопоставление, объединение или манипулирование коллекциями, к примеру Lists.

    Например, у нас есть поток данных (в нашем случае список строк), где каждая строка содержит название страны и ее город. Теперь мы можем обработать этот поток данных и выбрать только города Непала.

    Для этого мы можем использовать комбинацию Stream API и лямбда-выражений.

    Пример 6: использование лямбд в Stream API


    Результат выполнения:


    В приведенном выше примере обратите внимание на это выражение:


    Здесь мы используем такие методы, как filter(), map(), forEach() из Stream API, которые могут принимать лямбды в качестве параметра.

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

    Читайте также: