Функциональный интерфейс — это одна из наиболее важных концепций Java 8, которая на самом деле поддерживает лямбда-выражения, но многие разработчики не прикладывают достаточных усилий, чтобы понять его и тратить время на изучение лямбда-выражения и Stream API без предварительного понимания роли функционального интерфейса в Java 8. Если вы не знаете, что такое функциональный интерфейс и как его связывает лямбда, вы не сможете использовать мощные функции Java 8, например, лямбда-выражения и потоковый API . Без знания функционального интерфейса вы не сможете понять, где можно использовать лямбда-выражения в коде, но вам также будет сложно написать лямбда-выражение, которое ожидает метод, поэтому важно хорошо понимать функциональный интерфейс в Java 8.
В этой статье я попытаюсь восполнить этот пробел, объяснив, что такое функциональный интерфейс, что такое аннотация @Functional
, как они связаны с лямбда-выражением и как они помогают вам использовать лямбда-выражение в вашем коде. Итак, давайте начнем с самого первого, что такое функциональный интерфейс?
Что такое функциональный интерфейс в Java 8
Что ж, функциональный интерфейс — это не что иное, как интерфейс только с одним абстрактным методом, например EventListener
, Runnable
, EventListener
, Comparator
и т. Д. Вы можете видеть, что эти интерфейсы присутствовали в Java еще до JDK 8, но почему мы называем такой интерфейс функциональным интерфейсом?
Это очень хороший вопрос, и если вы немного знакомы с функциональным программированием, вы знаете, что он позволяет передавать код, то есть функцию, точно так же, как вы передаете данные или объект методу.
Эти интерфейсы только с одним абстрактным методом использовались для передачи кода, так же как вы передаете функцию на функциональном языке программирования, и поэтому они называются функциональным интерфейсом .
Например, вы можете напрямую передать код для сравнения объектов, создав класс Anonymous с помощью интерфейса Comparator
как показано ниже:
1
2
3
4
5
6
7
8
9
|
Collections.sort(list, new Comparator(){ public int compare(String s1, String s2){ return s1.length() - s2.length(); } }); |
Итак, если вы присмотритесь, вы увидите, что мы передаем код функции, используя эти интерфейсы. Они также известны как интерфейс стратегии, потому что это реализация шаблона стратегии, где код, который формирует стратегию, внедряется в код, который запускает эту стратегию во время выполнения.
Кстати, если вы не знаете, что такое шаблон «Стратегия», то я предлагаю вам перейти от 0 к 1: «Шаблоны проектирования — 24, которые имеют значение» — в Java , поскольку знание шаблона проектирования важно для эффективного кодирования в Java.
Итак, теперь, когда мы знаем, что такое функциональный интерфейс, давайте разберемся, как они связаны с лямбда-выражением , и насколько важно понимание функционального интерфейса для написания кода с использованием лямбда-выражения?
Ну, самое важное, что нужно помнить, это то, что единственное использование лямбда-выражения в Java — это преобразование их в функциональный интерфейс.
Это означает, что вы можете передать лямбда-выражение, если метод принимает функциональный интерфейс , что дополнительно означает, что вы можете передать лямбда-выражение всем существующим методам, которые принимают
Comparator
, Runnable
или любой другой интерфейс, который имеет только один абстрактный метод.
По этой причине лямбда-выражение в Java также называется типом SAM, где SAM означает «Единый абстрактный метод».
Что делает функциональная аннотация?
Теперь давайте посмотрим, что делает @Functional
аннотация? Будет ли интерфейс работать функционально, если вы просто поместите аннотацию @Functional
поверх этого? Ну, нет, это не так. На самом деле это
необязательно .
Это означает, что вы можете создать функциональный интерфейс без использования аннотации @Functioanl
же, как вы можете переопределить метод, не помещая аннотацию @Override
поверх метода. Тогда какова реальная цель аннотации @Functional
?
Ну, это может гарантировать, что интерфейс на самом деле имеет только один абстрактный метод, и это также дает подсказку инструментам, таким как Javadoc, что этот интерфейс является функциональным интерфейсом. Это очень похоже на аннотацию @Override
, которая помогает предотвратить человеческие ошибки, проверяя, что вы на самом деле переопределяете метод.
Подобно @Override
рекомендуется размещать аннотацию @Functional
поверх метода с помощью отдельных абстрактных методов, чтобы указывать инструментам, таким как Javadoc, на то, что они являются функциональным интерфейсом.
Весь новый функциональный интерфейс, добавленный в пакет java.util.function, аннотирован аннотацией @Functional
.
Кстати, у нас есть больше функциональных интерфейсов в JDK 8, в частности, функциональные интерфейсы общего назначения, такие как Predicate
, Supplier
, Consumer
, Function
, BiFunction
, UnaryOperator
и т. Д. См.
Java 8: основы для начинающих, чтобы больше узнать обо всех этих интерфейсах.
Эти функциональные интерфейсы позволяют передавать код в функцию в форме лямбда-выражения и позволяют создавать мощные методы, которые могут работать с этим кодом, например
filter (), который принимает Predicate и позволяет вам передать код, который принимает один аргумент и возвращает логическое значение.
Как функциональный интерфейс и Lamda Expression связаны
Как знание функционального интерфейса влияет на написание лямбда-выражения? Ну, если вы не понимаете функциональный интерфейс, вы не можете написать лямбда-выражение, которое можно преобразовать в этот функциональный интерфейс.
Например, метод merge()
интерфейса java.util.Map
принимает функцию BiFunction, но если вы не знаете, что такое функция BiFunction, вы не можете написать лямбду для этого.
BiFunction
— это функциональный интерфейс, который имеет метод, который принимает два аргумента T и U и возвращает объект R.
Это означает, что вы можете передать лямбду этому методу, который работает с двумя аргументами, и вернуть объект, например, merge(key, value, (v1, v2) -> v1 + v2)
здесь (v1, V2) -> v1 + v2
— это лямбда-выражение, которое можно преобразовать в экземпляр функционального интерфейса BiFunction.
Более простым примером является Predicate
который принимает тип T и возвращает логическое значение. Если вы посмотрите метод filter () класса Stream, он принимает предикат:
1
|
filter(Predicate predicate) |
Это означает, что вы можете передать любое лямбда-выражение, которое принимает один аргумент, и вернуть логическое значение этому методу, например, age -> age > 15 or s -> s.length == 15
, оба допустимы, но если вы не знаете, что такое Предикатный интерфейс, тогда вы не можете этого сделать.
Другим примером функционального интерфейса является Consumer
который принимает аргумент типа T и ничего не возвращает. Хорошее использование этого сделано в методе Iterate forEach()
Iterable в JDK 8, как показано ниже:
1
|
forEach(Consumer action) |
Вы можете видеть, что forEach () принимает Consumer, что означает, что вы можете передать ему лямбда-выражение, которое имеет один аргумент и ничего не возвращает или void, например
1
|
s -> System.out.println(s) |
Код System.out.println()
ничего не возвращает, он просто печатает строку в консоли.
Вы можете видеть, что если вы знаете функциональный интерфейс, то вы можете легко написать лямбда-выражение для передачи, следовательно, хорошее знание функционального интерфейса обязательно. Я предлагаю вам пройти через весь функциональный интерфейс в пакете java.util.function
и понять их.
Я расскажу о некоторых более сложных функциональных интерфейсах из пакета java.util.function
в следующих статьях, но если вы не можете ждать, я предлагаю вам пройти этот курс мастер-класса по Java 9, чтобы узнать больше о лямбдах и других Java 8 концепций.
Это все о том, что такое функциональный интерфейс в Java . Вы также узнали, какова роль аннотации @Functional
и почему для эффективного использования лямбда-выражения в вашем коде в Java 8 требуется хорошее знание функционального интерфейса. Если вы еще не начали с Java 8, я предлагаю вам сделать это сейчас, потому что в ближайшие годы все будут кодировать, используя Java 8, и если вы не знаете лямбда-выражения и новых функций, представленных в Java 8, вы останетесь позади.
Другие учебники и ресурсы по Java 8 для дальнейшего изучения
Как отсортировать HashMay по ключам и значениям, используя лямбды?
Как использовать карту и flatMap в Java 8?
Как сделать Map Reduce в Java 8?
Как преобразовать лямбда-выражение в ссылку на метод в Java 8?
Новые возможности Java SE 8 — полное руководство
Спасибо за чтение этой статьи до сих пор. Если вам нравится мое объяснение функционального интерфейса и аннотации @Functional
поделитесь с друзьями и коллегами. Если у вас есть какие-либо вопросы или пожелания, оставьте комментарий.
Смотрите оригинальную статью здесь: Что такое функциональный интерфейс в Java 8? @ Функциональная аннотация и примеры
Мнения, высказанные участниками Java Code Geeks, являются их собственными. |