Давайте возьмем случай, когда переменная используется Lambda.

Возьмем класс (Doge), использующий функциональный интерфейс (PrintCoin), который печатает количество монет.

Функциональный интерфейс выглядит следующим образом: он использует один абстрактный метод print().

@FunctionalInterface
interface PrintCoin{
    void print();
}

Класс Doge выглядит так, мы определяем функцию как

() -> System.out.println('Вот ваш doge = '+coin);

который сопоставляется с print()

class Doge{

    int coin;

    public void getDoge(){
        PrintCoin printCoin = () -> System.out.println("Here's your doge = "+coin);
        printCoin.print();
    }

    public static void main(String []args){
        Doge doge = new Doge();
        doge.getDoge();
    }
}

Вывод будет выглядеть так

Here's your doge = 0

Супер просто! Лямбда просто потребляет значение экземпляра.

Значение монеты по умолчанию равно 0. Давайте инициализируем значения.

Вуаля! Отсюда становится очень легко!

Переменная экземпляра, инициализированная в методе

В предыдущем примере монета была инициализирована значением по умолчанию. Давайте инициализируем значение внутри метода.

@FunctionalInterface
interface PrintCoin{
    void print();
}

class Doge{

    int coin;

    public void getDoge(){
        coin = 100; //init inside method
        PrintCoin printCoin = () -> System.out.println("Here's your doge = "+coin);
        printCoin.print();
    }

    public static void main(String []args){
        Doge doge = new Doge();
        doge.getDoge();
    }
}

Вывод,

Here's your doge = 100

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

Переменная экземпляра, инициализированная внутри Lambda

Давайте напрямую инициализируем значение монеты внутри Lambda.

Можем ли мы манипулировать значением после инициализации? ДА ДА!

@FunctionalInterface
interface PrintCoin{
    void print();
}

class Doge{

    int coin;

    public void getDoge(){
        PrintCoin printCoin = () -> {
            coin = 50; //init inside lambda 
            coin = coin + 50; //manipulating value inside lambda
            System.out.println("Here's your doge = "+coin);
        };
        printCoin.print();
    }

    public static void main(String []args){
        Doge doge = new Doge();
        doge.getDoge();
        
        //checking the value after manipulation outside lambda
        System.out.println("Doge value ="+ doge.coin);
    }
}

Вывод? ты знаешь это!

Here's your doge = 100
Doge value =100

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

Ссылочные переменные и лямбда

Мы добавим список целых чисел, определяющих купленные монеты.

Затем мы добавим общее количество купленных монет.

@FunctionalInterface
interface PrintCoin{
    void print();
}

class Doge{

    int coin;

    List<Integer> coinBought = Arrays.asList(80,20); //reference

    public void getDoge(){
        PrintCoin printCoin = () -> {
            coin = 50;
            coin += coinBought.stream().reduce(0, (coin1,coin2) -> coin1+coin2); //summation of list
            System.out.println("Doge to the MOoon! Bag it sis = "+coin);
        };
        printCoin.print();
    }

    public static void main(String []args){
        Doge doge = new Doge();
        doge.getDoge();

        System.out.println("Doge value = "+ doge.coin);
    }
}

Вывод выглядит так,

Doge to the MOoon! Bag it sis = 150
Doge value =150

Как мы видим, мы получили доступ к ссылкам внутри лямбды.

Идеально!

Давайте попробуем инициализировать ссылку внутри лямбда

package com.company;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

@FunctionalInterface
interface PrintCoin{
    void print();
}

class Doge{

    int coin;

    List<Integer> coinBought;

    public void getDoge(){
        PrintCoin printCoin = () -> {
            coin = 50;
            coinBought = new ArrayList(); //init reference inside lambda still remains local to lambda
            coinBought.add(80);
            coinBought.add(20); 
            coin += coinBought.stream().reduce(0, (coin1,coin2) -> coin1+coin2);
            System.out.println("Doge to the MOoon! Bag it sis = "+coin);
        };

        printCoin.print();
    }

    public static void main(String []args){
        Doge doge = new Doge();
        doge.getDoge();

        System.out.println("Doge value = "+ doge.coin);
    }
}

Ссылка была инициализирована локально для лямбда-функции.

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

package com.company;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

@FunctionalInterface
interface PrintCoin{
    void print();
}

class Doge{

    int coin;

    List<Integer> coinBought;

    public void getDoge(){
        PrintCoin printCoin = () -> {
            coin = 50;
            coinBought = new ArrayList(); //init is local to lambda function
            coinBought.add(80);
            coinBought.add(20);
            coin += coinBought.stream().reduce(0, (coin1,coin2) -> coin1+coin2);
            System.out.println("Doge to the MOoon! Bag it sis = "+coin);
        };

        coinBought.add(30); //ERROR
        printCoin.print();
    }

    public static void main(String []args){
        Doge doge = new Doge();
        doge.getDoge();

        System.out.println("Doge value = "+ doge.coin);
    }
}

Вывод,

Exception in thread "main" java.lang.NullPointerException
 at com.company.Doge.getDoge(Main.java:28)
 at com.company.Doge.main(Main.java:34)

Почему это происходит? потому что выполненная инициализация является локальной для метода.

В заключении,

Переменные Insatnce можно инициализировать/манипулировать в любом месте внутри метода

Переменные экземпляра можно инициализировать/манипулировать внутри любых лямбда-функций

Это все люди!

Играйте больше! Дайте мне знать, если я пропустил какие-либо сценарии.

Ваше здоровье!