Лямбда - любовь-ненависть "->"

интервью Java
Лямбда - любовь-ненависть "->"

Мало знаний, большой вызов! Эта статья участвует в "  Необходимые знания для программистов  «Творческая деятельность

Спасибо

  • Не ожидал этогообъем чтенияиКоллекцияЭто будет так высоко, я очень благодарен своим друзьям за то, что они дали мне мнения и предложения, и у меня есть мотивация снова улучшить и обновить эту статью ххх!

казатьсяJava,распределенный,Шаблоны проектированияСвязанные будут больше соответствовать вкусам копающих друзей, ха-ха, все желающие могут взглянуть, вашиСледите и комментируйтеЭто моя самая большая мотивация для Gengwen. Предыдущая мотивация былаДеятельность самородковХахаха (нет).

написать впереди

  • Говоря о новых функциях Java 8, нашей первой реакцией должно быть появление лямбда-выражений и функциональных интерфейсов. Сказать, что ta в определенной степени «оптимизировал» простоту кода? Или, в определенной степени, ta усложнил чтение и отладку для программистов, вызывая головную боль у многих программистов. В этом выпуске продолжим "Разговоры о Java", часть новых возможностейЛюбовь и ненависть Лямбда.

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

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

приложение в треде

image.png

традиционный способ

Создайте одноразовый класс

//一次性的类,用在new Thread中充当Runnable对的实现类
class runnable implements Runnable{

    @Override
    public void run() {
        System.out.println("我在路上");
    }
}

public class lambdaTest {
    public static void main(String[] args) {
        runnable runnable = new runnable();
        Thread thread1 = new Thread(runnable);
    }
}

(слегка оптимизированный) анонимный внутренний класс

Thread thread1 = new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println("我在路上");
            }
        });

эффект

  • Избегайте определения слишком большого количества анонимных внутренних классов.
  • Сделайте код лаконичным
  • Упростите код, оставив только основную логику

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

Определение: любой интерфейс, если только содержиттолько одинабстрактный метод, то это функциональный интерфейс

public interface Runnable{
    void run();
}

Чтобы избежать добавления функций в этот интерфейс позже, что приведет к тому, что интерфейс будет иметь несколько функций, что больше не является функциональным интерфейсом, мы можем объявить **@FunctionalInterface** над классом интерфейса.image.png

Все типы Lambda являются интерфейсом

  • Само лямбда-выражение является реализацией этого интерфейса.

image.png

Если он определен как класс реализации, будет сообщено об ошибке

  • Когда мы компилируем программу, мы не знаем, какой подкласс объекта, который мы наконец создали, и мы не можем знать это до времени выполнения, а затем мы можем сделать так, чтобы это указывало науказывает на различные классы,Можетвызывать различные методы подкласса, что значительно улучшает масштабируемость программы

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

image.png image.png

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

Demo

 //接口定义
    interface parseIntNum{
        //定义一个String转化成Integer的方法
        int pass(String s);
    }
    public static void main(String[] args) {
        parseIntNum parseIntNum1;
        parseIntNum parseIntNum2;
        //原始lambda
        parseIntNum1 = (str)-> Integer.parseInt(str);
        System.out.println(parseIntNum1.pass("1"));
        //方法引用改进版本
        parseIntNum2 = Integer::parseInt;
        System.out.println(parseIntNum2.pass("1"));
    }

image.pngТак называемая ссылка на метод означает, что если определенныйметоды, которые уже существуют,егоподписатьифункции, определенные в интерфейсеТочно так же вы можете напрямую передать ссылку на метод. Поскольку метод, определенный интерфейсом parseIntNum, является int pass(String s) иIntegerПо сравнению со статическим методом int parseInt(String s) помимо имени методапараметры методапоследовательный,возвращаемый типТо же самое, вот как мы говоримПодпись совпадает, вы можете напрямую передать ссылку на метод

Как писать ссылки на методы

  • Это на самом деле очень просто, просто используйтеоператорДвойное двоеточие** "::"**

Общие ссылки на методы

image.png

Общие формы цитирования

имя класса:: статическое имя метода

вызов статического метода класса

  • Фактически, наше использование Integer::parseInt выше эквивалентно вызову статического метода IntegerparseInt

image.png

объект: метод экземпляра

Вот немного средней школы хххх

class Naruto{
    public static void Rasengan(){
        System.out.println("螺旋丸");
    }
}
//接口定义
interface Ninja{
    //定义一个奥义方法
    void aoyi();
}
public class methodQuote {
    //通过引用Naurto的螺旋丸
    Ninja ninja=Naruto::Rasengan;
    //再发动奥义
    ninjia.aoyi();
}

тип данных: новый

 public static void main(String[] args) {
     //方式一
        IntFunction<int []> arr1 = new IntFunction<int[]>() {
            @Override
            public int[] apply(int num) {
                return new int[num];
            }
        };
        arr1.apply(10);
     //方式二(方法引用)
        IntFunction<int []> arr2 = int[]::new;
        arr2.apply(10);

    }
  • Кроме того, существует множество других форм, поэтому я не буду здесь вдаваться в подробности.

Обычно используется для разработки

Общие советы: обход массива и печать

Сравнивая три метода, мы видим простоту

ArrayList<Integer> arrayList=new ArrayList<>();
        arrayList.add(1);
        arrayList.add(2);
        arrayList.add(3);
//匿名内部类
        arrayList.forEach(new Consumer<Integer>() {
            @Override
            public void accept(Integer integer) {
                System.out.println(integer);
            }
        });
//lambda优化
		arrayList.forEach((integer)-> System.out.println(integer));	
//方法引用打印,用方法引用替代了我们的匿名内部类(相当于替代了lambda)
        arrayList.forEach(System.out::println);

Путешествие по карте

		Map<Integer, String> map = new HashMap<>();
        map.forEach((k,v)->System.out.println(v));

Область действия лямбда-выражения (приложение 11-03)

Спасибо друзьям в области комментариев "Как может быть настоящая любовь в мире" за упоминание этого вопроса, добро пожаловать друзьяучиться вместе!

Доступ к локальным обычным переменным

  • можно только сослатьсяfinalвнешняя локальная переменная

то есть: не может бытьlambdaВнутренне измените локальные переменные, определенные за пределами домена, иначе произойдет ошибка компиляции.

image.png

  • В особых случаях локальные переменные не могут быть объявлены какfinal, но не должен модифицироваться последующим кодом (т.е.неявно имеет окончательныйсемантика)

image.png

Прерывает неявный финал (снова изменено)

image.png

package com.melo.notes.lambdaTest;

public class TestFinal {
    interface MeiYan{
        Integer change(String str);
    }

    public static void main(String[] args) {
        //定义局部变量
        String temp = "222";
        //写成一行可以不用return
        MeiYan meiYan = (str -> Integer.valueOf(str+temp));
        //再次修改,不符合隐式final定义
        temp = "333";
        Integer str =meiYan.change("111") ;
        System.out.println(str);
    }
}
  • Объявление переменной с помощью локальной переменной не допускается.то же имяпараметры или локальные переменные.

доступ к локальной ссылочной переменной

image.png

import java.util.ArrayList;
public class TestArray {

    interface MeiYan{
        Integer change();
    }
    void testArrayList(){
        ArrayList<String> list = new ArrayList<>();
        list.add("111");
        //访问外部引用局部引用变量
        MeiYan meiYan = (() -> Integer.valueOf(list.get(0)));
        //修改局部引用变量
        list.set(0,"222");
        Integer str =meiYan.change();
        System.out.println(str);
    }
    public static void main(String[] args) {
        new TestArray().testArrayList();
    }
}
  • Нет проблем с доступом к ссылочным переменным. Поскольку лямбда-выражение может воспринимать внешние изменения ссылочной переменной, проблем с синхронизацией данных не возникнет.

Подробности смотрите ниже"понимать" имеет более подробное объяснение

Доступ к статическим переменным и переменным экземпляра

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

image.png

код

public class TestFinal {
    //静态变量
    static String StaticTemp;
    //实例变量
    String instanceTemp;

    interface MeiYan{
        Integer change(String str);
    }
    void testStatic(){
        StaticTemp="222";
        MeiYan meiYan = (str -> Integer.valueOf(str+StaticTemp));
        StaticTemp="333";
        Integer str =meiYan.change("111") ;
        System.out.println(str);
    }
    public static void main(String[] args) {
        new TestFinal().testStatic();
    }

понимать

Разница между переменной экземпляра и локальной переменной

Ключевой вопрос здесь звучит так: в чем разница между переменными экземпляра и локальными переменными?

  • переменные экземпляра хранятся вкучаначальство

Куча распределяется между потоками.

  • в то время как локальные переменные хранятся вкучаначальство

Могут быть соответствующие проблемы с потоками (см. ниже)

проблема с нитью

Например, поток A выделяет переменную temp

  • Возможно, что Lambda используется в другом потоке B. Поток B, использующий Lambda, может получить доступ к временной переменной после того, как поток A, выделивший переменную, вернет временную переменную.

Проблема с синхронизацией данных

Подумайте о наших обычных методах.Параметры метода живут только в пространстве стека методов, а { } нашей лямбда фактически эквивалентна блоку методов.

  • если мы здесьблок методадоступ к внешней переменной, которая является простообщий тип данныхЕсли это так, это эквивалентно простому доступу к копиикопировать. Когда эта переменная изменяется извне, лямбдавнутренний(только копия) не знает об изменении этой переменной.

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

Расширения -- передавать по значению или по ссылке?

  • Здесь только упоминается, что будут ограничения на локальные переменные обычных типов данных, а как быть с локальными переменными ссылочных типов? Это включает в себя то, что является параметром, передаваемым в Java?передать по значениювсе ещепройти по ссылке.

Сначала займитесь питомцем, и я буду обновлять блог об этом в этой колонке в будущем! ! !

Решение вопроса

В начале был вопрос, вроде бы в ссылке на метод опущен параметр, так кем оперируем Intger.parseInt?

  • На самом деле он путает лямбду, параметр при определении лямбды вообще не является фактическим параметром

Скажем, этот параметр, простоПодавать тело методаДа, но он будет использоваться в теле метода. И у нас есть все используемые ссылки на методы. Предпосылка состоит в том, что параметры такие же, как и возвращаемое значение, и тело метода также является тем, чего мы хотим достичь. В настоящее время нам, естественно, не нужно писать тело метода, тогдаПараметры, от которых зависит тело метода, естественно, не пригодятся.

напиши в конце

  • Я собираюсь недавно начать насыщенный проект, и более глубокое понимание этих базовых знаний может быть использовано в будущем при подготовке к собеседованию. В настоящее время у меня нет глубокого понимания. Если есть какие-либо ошибки , я надеюсь указать!

В этом столбце также будут периодически обновляться некоторые элементы Java.Базовые знания и лицом к лицу, заранее заложите основу для будущих интервью!