Javase8, выпущенный в 2013 году, будет включать план под названием Lambda Project, который описан в драфте JSR-335 в июне этого года.
JSR-335 представил закрытие на Java. Закрытие существует во многих популярных языках, таких как C ++, C#. Закрытие позволяет нам создавать указатель функции и передавать его в виде параметра. В этой статье мы примерно рассмотрим характеристики Java8 и представим выражения Lambda. И я постараюсь поместить несколько образцов программ, чтобы объяснить некоторые концепции и грамматику.
Язык программирования Java предоставляет нам концепцию интерфейса, а метод абстрактного можно определить в интерфейсе. Интерфейс определяет API и надеется, что пользователи или поставщики реализуют эти методы. Много раз мы не создаем независимые классы реализации для некоторых интерфейсов.
Анонимное использование широко используется. Самая распространенная сцена, используемая в анонимном внутреннем классе, - это процессор событий. Во -вторых, анонимные внутренние классы часто используются в многочисленных программах.
Как и мы обсуждаем, анонимный класс - это реализация данного интерфейса ниндзя. Обычно мы передаем объект этого класса реализации в качестве параметра методу, а затем этот метод будет вызывать метод класса реализации в класс реализации внутренне. Поэтому этот интерфейс называется интерфейсом обратного вызова.
Хотя анонимные категории используются повсюду, у них все еще есть много проблем. Первая главная проблема - сложность. Эти классы заставляют уровни кода выглядеть грязным и сложным, также известным как вертикальный привод. Во -вторых, они не могут получить доступ к нефинальным членам класса упаковки. Ключевое слово этого станет очень запутанным. Если анонимный класс имеет то же имя члена, что и его класс упаковки, внутренние переменные будут охватывать переменные внешнего элемента. Потому что это ключевое слово заслуживает самого анонимного объекта, а не его объекта инкапсуляции.
Public void anommousexample () {string nonfinalVariable = "Nonformal Exmple"; Переменная запуска "; // Ниже строительство дает ошибку компиляции. //System.out.println ("-> "" " + nonfinalVariable); System.out.println ("-> "" + переменная); println ("->" + this.variable);}}). Вывод:
-> Запустить варьирование метода-> Заполненный элемент класса
Этот пример объясняет проблему, которую я упоминал выше, и Lambda выражение почти решает все проблемы, вызванные анонимными внутренними классами. Прежде чем мы дальше исследуем выражение Lambda, давайте посмотрим на функциональные интерфейсы.
Функциональные интерфейсы
Функциональные интерфейсы - это интерфейс только с одним методом, который представляет этот контракт метода.
Только один в определении выше не так просто. Я не понимаю этот абзац.
В следующем примере ясно показывает, как понять концепцию функциональных интерфейсов.
Интерфейс runnable {void run ();} // functionalintface foo {boolean equals (Object obj);} // не функциональный; Функциональный; не функциональный; Та же самая подписьБольшинство интерфейсов обратного вызова являются функциональными интерфейсами. Например, выполняемый, вызов, компаратор и т. Д. Ранее его называли SAM (метод одного абстрактного)
Lambda выражение
Как мы уже говорили, основная проблема анонимной категории заключается в том, что уровень кода выглядит грязно, то есть вертикальная привилегия. Lambda выражение выглядит как метод. Они имеют формальный список параметров и блокирование этих параметров.
(String S) -> s.lengh; () -> 43;
Приведенный выше пример означает, что первое выражение получает строковую переменную в качестве параметра, а затем возвращает длину строки. Второй без каких -либо параметров и вернуть 43. Наконец, третий принял два целых числа X и Y и вернулся к миру.
Прочитав много слов, наконец, я могу привести пример первого выражения Lambda.
Public Class FirstLambdaExpression {public String variable = "variable verail"; String nonfinalVariable = "Это не конечная переменная"; ; System.out.println ("->" "" " + this.varail Вывод:
-> Метод локальная переменная-> переменная уровня класса
Вы можете сравнить разницу между использованием выражений Lambda и анонимным внутренним классом. Мы можем четко сказать, что написание анонимных категорий с использованием Lambda Expression решает проблему видимости переменной. Вы можете взглянуть на аннотации в коде.
Синтаксис выражения General Lambda включает в себя список параметров, ключевое слово стрелки "->"-основной корпус. Субъектом может быть выражение (одно -линейное утверждение) или многочисленное предложение. Если это выражение, оно будет рассчитано и возвращено. Перерыв и продолжение может использоваться только внутри цикла.
Почему выбирают эту специальную грамматическую форму, потому что в настоящее время этот стиль обычно находится в C# и Scala, что также является общим написанием выражения Lambda. Этот грамматический дизайн в основном решает сложность анонимного типа. Но в то же время он также очень гибкий. Результатом выражения является его собственная возвратная стоимость. Эта гибкость может сделать код простым.
Экспрессия Lambda используется в качестве анонимного, поэтому их можно гибко использовать в других модулях или других выражениях лямбда (вложенные выражения лямбда).
// Lambda Exposition заключается в блоке параметров методов .//target (() -> {System.out.println («Запуск в разных потоках»);});
Если вы посмотрите на выражение Lambda, вы увидите, что тип целевого интерфейса не является частью выражения. Компилятор помогает сделать вывод типа и окружающей среды выражения Lambda.
Выражение Lambda должно иметь целевой тип, и они могут адаптироваться к любому возможному типу целевого. Когда целевой тип является интерфейсом, необходимо выполнить следующие условия для правильной компиляции:
Поскольку компилятор может знать тип и число параметров через оператор Target Type, в выражении Lambda, объявление типа параметра может быть опущено.
Comporator C = (S1, S2) -> S1.comparetoIgnoreCase (S2);
Более того, если метод, объявленный в целевом типе
ActionListenr Listenr = Event-> Event.getHen ();
Задается очень очевидный вопрос, почему Lambda Express не указанное имя метода?
Ответ: выражение лямбда может использоваться только для функционального интерфейса, в то время как функциональный интерфейс имеет только один метод.
Когда мы определяем функциональный интерфейс для создания выражений Lambda, компилятор может воспринимать подпись закона о функциональном интерфейсе китайского языка и проверить, соответствует ли данное выражение.
Эта гибкая грамматика помогает нам избежать использования анонимной вертикальной привилегии, и она не принесет горизонтальную привалу (очень длинное предложение).
Грамматика выражения Lambda связана с контекстом, но это не первый раз. Алмазные операторы, добавленные Java SE 7, также имеют эту концепцию, которая выводится по контексту.
void invoke (Runnable r) {r.run ()} void future invoke (callable r) {return c.compute ()} // выше -два метода Onal Interfacefuture s = invoke (() -> "end"); / Какой вызов будет вызван?
Ответ на приведенный выше вопрос - вызвать метод получения параметра Callable. В этом случае компилятор будет разрешаться посредством нагрузки различных типов параметров. Когда существует более одного применимого метода загрузки, компилятор также проверяет совместимость выражения Lambda и соответствующий тип цели. Проще говоря, приведенный выше метод вызова вернется, но только один метод вызова имеет возвратное значение.
Выражения Lambda могут быть явно преобразованы в указанные типы целей, если они совместимы с соответствующими типами. Глядя на следующую программу, я реализовал три типа вызова, и все они преобразовали ее в тип класса.
Public Class FirstWithLambDaexPressions {public static void main (string [] args) {listl = arrayslist (callial)-> «Callable 1», (Call Able) ()-> «Callable 2», (Callible) (Callable))-> «Callable 3»); ) {e1.printStackTrace ();} e.shutdown ();} public void pountist (список списков) Throws Interuptexception, executionExcepti on {for (Future: List. System.out.println (future.get ()); }}}Как мы обсуждали ранее, анонимные категории не могут получить доступ к нефинальным переменным в окружающей среде. Но нет такого ограничения в выражении Lambda.
В настоящее время определенные функциональные интерфейсы применимы только к интерфейсу. Я попытался создать выражение лямбды только одного абстрактного метода, но была сделана ошибка компиляции. Согласно JSR -335, будущая версия Lambda Expression может поддерживать функциональные классы.
Метод цитата
Методы упоминаются как справочный метод, не вызывая его.
Выражение Lambda позволяет нам определить анонимный метод и использовать его в качестве экземпляра функционального интерфейса. Методы очень похожи на выражение Lambda.
System :: getProperty "ABC" :: PlayString :: SefienSuper :: toStringArrayList :: new
Приведенный выше оператор показывает общий синтаксис метода и ссылку на конструктор. Здесь мы видели нового операционного персонажа »:::: Double Colon). Я не знаю точного имени как этот оператор, но JSR называет его как сепараторы, и страница Википедии называет его как операция анализа области .
Целевая ссылка или приемник расположены за поставщиком и сепараторами. Это образует выражение, которое может цитировать метод. В последнем утверждении название метода «новое». Это выражение цитирует метод структуры класса ArrayList (ссылка на конструктор в следующем разделе)
Прежде чем вы поймете это, я хочу позволить вам увидеть силу цитируемого метода.
Import java.util.arrays; = {Новый сотрудник ("nick"), новый сотрудник ("Робин"), новый сотрудник ("Джош"), новый сотрудник ("Andy"), новый сотрудник ("Mark")}; Перед сортировкой: «); Dirmplovereee (сотрудники); Arrays.sort (сотрудники, сотрудники :: mycompare); System.out.println (" После сортировки: "); Aslist (сотрудники)) {System.out.print (emp.name+",");} System.out.println (); (Employeee EMP1, Employee EMP2) {return Emp1.name.compareto (emp2.name);}} Вывод:
Перед сортировкой: Ник, Робин, Джош, Энди, Марк, после сортировки: Энди, Джош, Марк, Ник, Робин,
Вывод не особенный. Статический метод MyCompare получает два объекта сотрудника и возвращает их имена для сравнения.
В основном методе я создал другой массив сотрудника и передал его в метод Arrays.sort, чтобы ссылаться на массив выражения (сотрудник :: mycompare).
Подождите минутку, если мы посмотрим на Javadoc, вы обнаружите, что второй параметр метода вида - тип кораратора, но мы передаем статический метод ссылки на сотрудника. Важная проблема здесь.
Давайте посмотрим, почему. Метод Arrays.sort ожидает экземпляра компаратора, и этот компаратор является функциональным интерфейсом, что означает, что у него есть только один метод, то есть сравнить. Здесь мы также злонамеренно передаем выражение Lambda, которое обеспечивает реализацию метода Compaare в этом выражении. Но в нас у нашего класса сотрудников уже есть метод сравнения. Просто их имена разные.
Когда есть несколько методов одного имени, компилятор выберет лучшее сопоставление в соответствии с целевым типом. Чтобы понять, посмотрите на пример:
Public Static Int MyCompare (Employeee EMP1, Employee EMP2) {return Emp1.name.compareto (emp2.name);} // Другой метод с тем же именем, что и. {{) {{) {{Return int1.compareto (int2);} Я создал два разных массива для сортировки.
Сотрудник [] Сотрудники = {новый сотрудник ("nick"), новый сотрудник ("Робин"), новый сотрудник ("Джош"), новый сотрудник ("Andy"), новый сотрудник ("Mark")}; ins = {1, 4, 8, 2, 3, 8, 6}; Теперь я выполняю следующие две строки кода
Arrays.sort (сотрудники, сотрудник :: mycompare);
Здесь метод ссылок в двух строках кода одинаков (сотрудник :: MyCompare).
Не вводятся в заблуждение статическим методом, мы также можем создать ссылку на пример метода. Для статических методов мы используем названия классов :: Имя метода для написания метода.
Приведенный выше пример довольно хорош, но нам не нужно писать метод для сравнения целого числа, поскольку Integer реализовано сопоставимо и обеспечивает сравнение метода реализации. Итак, мы просто используем следующую строку напрямую:
Arrays.sort (ints, Integer :: CompareTo);
Видя это, вы чувствуете себя немного смущенным? Нет? Затем позвольте мне путать вас здесь. Способность члена упоминается :: Это должен быть объект раньше, но почему предложение здесь действительно законно.
Ответ: этот тип оператора позволяет использовать в некоторых конкретных типах. INTEGER - это тип данных, и для типа данных этот оператор разрешен.
Если мы превратим метод сотрудника MyCompare в неэтиацию, то используйте: работник :: MyCompare, будут ошибки компиляции: не найдено подходящего метода.
Конструктивная ссылка на метод
Ссылки конструктора используются в качестве класса, который ссылается на конструктор без указанной институционализации.
Справочник по конструктивному методу является новой особенностью Javase 8. Мы можем построить ссылку на конструктивный метод и передать его в качестве параметра целевому типу.
Когда мы используем его для ссылки, мы цитируем один существующий метод для их использования. Точно так же при использовании конструктивной ссылки на метод мы создаем ссылку на существующие конструктивные методы.
В предыдущем разделе мы видели имя грамматики, на которое ссылается конструктор :: new, который выглядит как ссылка на метод. Ссылка на этот построенный метод может быть назначен экземплярам целевых функциональных интерфейсов. В этом случае может быть несколько конструкторов.
Для меня трудно написать первый конструктивный метод. В конце концов, я много времени потратил много времени, и, наконец, «Ах, я нашел ...», посмотрите на следующую процедуру.
Public Class ConstructorReerences {public static void main (string [] ar) {myInterface in = myClass :: new; } Вывод:
-> com.myclass@34e5307e
Это выглядит немного удивительно, верно?
Этот пример вызвал еще одну проблему в моем сердце: как создать конструктивный метод с параметром? Посмотрите на процедуру ниже:
Public Class ConstructorReerences {Public Static void Main (String [] ar) {emlPoyepRoder Provider = employee :: new; ; возраст) {this.name = name; Вывод:
-> Имя сотрудника: Джон-> Возраст сотрудника: 30
Перед прочтением этой статьи давайте посмотрим на самую крутую функцию в методе Javase8-Default
Методы по умолчанию
Javase8 представит концепцию, называемую методом по умолчанию. Ранняя Java -версия интерфейса имеет очень строгий интерфейс. В предстоящей версии Java разрешена реализация метода в интерфейсе. Не много ерунды, посмотрите на следующее:
Общедоступный класс по умолчанию meThods {public void main (string [] ar) {normalInterface = New NormalInterfaceImpl (); System.out.println ("-> mydefaultmethod");}} class normalInterfaceImpl ImplemeLemerInterface {@Override public void mynormalmethod () {) system.out.println ("-> mynormalmethod");}} Вывод:
-> MyDefaultMethod
Приведенный выше интерфейс объявляет два метода, но класс реализации этого интерфейса реализует только один из них, потому что MyDefaultMethod использует модификаторы по умолчанию, и он предоставляет блок метода для реализации по умолчанию. Правила тяжелой нагрузки GM все еще вступают в силу здесь. Если класс реализации реализует метод в интерфейсе, это будет метод в классе вызовов при вызове, в противном случае будет вызвана реализация по умолчанию.
Интерфейс интегрированного родительского интерфейса может увеличивать, изменять и удалять реализацию по умолчанию родительского интерфейса.
Interface ParentInterface {void изначально (); -> изначально nomal ");} void изначально default (); // Теперь нормальный метод} В этом примере ParentInterface определяет два метода, один нормальный, а другой реализован по умолчанию.
Представьте себе, что класс унаследовал класс C, осознал, что интерфейс I и C имел метод, и метод, который предоставил метод по умолчанию, в котором при условии, что метод по умолчанию был совместимым. В этом случае метод в C будет уделять приоритет методу по умолчанию в I, и даже метод в C по -прежнему остается приоритетом, когда метод является абстрактным.
Открытый класс DefaultMethods {public static void main (string [] ar) {interfax inmp = new NormalInterfaceImpl (); ;}} интерфейс Interfaxe {public void defaultmethod () default {System.out.println ("-> Interfaxe"); Вывод:
-> ParentClass
Вторым примером является то, что мой класс реализовал два разных интерфейса, но оба из двух интерфейсов предоставляют один и тот же оператор с одним и тем же методом реализации по умолчанию. В этом случае компилятор не сможет выяснить, что происходит. Это можно сделать следующими способами.
Public Class DefaultMethods {public static void main (string [] ar) {FirstInterface inmp = new NormalInterfampl (); );}} интерфейс SecondInterface {public void defaultmethod () default {System.out.println ("-> SecondInterface"); Вывод:
-> SecondInterface
Теперь мы прочитали представление о закрытии Java. В этой статье мы вступили в контакт с функциональными интерфейсами и закрытием Java, которые поняли выражение Java Lambda, ссылки на методы и ссылки на конструктор. И мы также написали пример Hello World выражения Lambda.
Javase8 скоро появится.