final์€ ์•„๋‹ˆ์ง€๋งŒ final์ฒ˜๋Ÿผ

์ž๋ฐ”์—์„œ final ํ‚ค์›Œ๋“œ๊ฐ€ ์„ ์–ธ๋˜์ง€ ์•Š์€ ๋ณ€์ˆ˜์ง€๋งŒ, ๊ฐ’์ด ์žฌํ• ๋‹น๋˜์ง€ ์•Š์•„ final ๊ณผ ์œ ์‚ฌํ•˜๊ฒŒ ๋™์ž‘ํ•˜๋Š” ๊ฒƒ์„ effectively final์ด๋ผ๊ณ  ํ•œ๋‹ค. ์ด ๊ฐœ๋…์€ ์ž๋ฐ” 8์—์„œ ๋„์ž…๋˜์—ˆ๋Š”๋ฐ, ์ต๋ช… ํด๋ž˜์Šค(Anonymous Classes) ๋˜๋Š” ๋žŒ๋‹ค์‹(Lambda Expressions)์ด ์‚ฌ์šฉ๋œ ์ฝ”๋“œ์—์„œ ์‰ฝ๊ฒŒ ์ฐพ์•„๋ณผ ์ˆ˜ ์žˆ๋‹ค.

์ต๋ช… ํด๋ž˜์Šค ๋˜๋Š” ๋žŒ๋‹ค์‹์—์„œ๋Š” ์ฐธ์กฐํ•˜๋Š” ์™ธ๋ถ€ ์ง€์—ญ ๋ณ€์ˆ˜๊ฐ€ final๋กœ ์„ ์–ธ๋๊ฑฐ๋‚˜ ์„ ์–ธ๋œ ํ›„ ์ฐธ์กฐ๊ฐ€ ๋ณ€๊ฒฝ๋˜์ง€ ์•Š๋Š” effectively final์ธ ๊ฒฝ์šฐ์—๋งŒ ์ ‘๊ทผ ๊ฐ€๋Šฅํ•˜๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด ์•„๋ž˜ ์˜ˆ์ œ์™€ ๊ฐ™์ด ์ฐธ์กฐํ•˜๋Š” ์ง€์—ญ ๋ณ€์ˆ˜๊ฐ€ ๋‚ด๋ถ€์—์„œ ๋ณ€๊ฒฝ๋œ๋‹ค๋ฉด โ€œlocal variables referenced from a lambda expression must be final or effectively finalโ€ ์˜ค๋ฅ˜ ๋ฉ”์‹œ์ง€์™€ ํ•จ๊ป˜ ์ปดํŒŒ์ผ ์—๋Ÿฌ๊ฐ€ ๋ฐœ์ƒํ•œ๋‹ค.

// Anonymous Classes
public void someMethod() {
    int count = 0;
    Runnable runnable = new Runnable() {
        @Override
        public void run() {
            // "local variables referenced from an inner class
            // must be final or effectively final"
            count++;
        }
    };
}

// Lambda Expressions
public void someMethod() {
    List<Integer> list = Arrays.asList(1, 2, 3, 4);
    Integer criteria;
    
    for (Integer integer : list) {
        if (integer > 2) {
            criteria = 3;
            // "local variables referenced from a lambda expression
            // must be final or effectively final"
            list.removeIf(o -> o.equals(criteria));
        }
    }
}


effectively final

๊ทธ๋ ‡๋‹ค๋ฉด ์ •ํ™•ํžˆ ์–ด๋–ค ๊ฒฝ์šฐ๋ฅผ effectively final์ด๋ผ๊ณ  ๋งํ•˜๋Š” ๊ฒƒ์ผ๊นŒ? ์ž๋ฐ” ์–ธ์–ด ์ŠคํŽ™์„ ์‚ดํŽด๋ณด๋ฉด ๋‹ค์Œ๊ณผ ๊ฐ™์€ ์กฐ๊ฑด์„ ๋งŒ์กฑํ•˜๋Š” ์ง€์—ญ ๋ณ€์ˆ˜(local variables)๋Š” effectively final๋กœ ๊ฐ„์ฃผํ•œ๋‹ค.

  • final๋กœ ์„ ์–ธ๋˜์ง€ ์•Š์•˜๋‹ค.
  • ์ดˆ๊ธฐํ™”๋ฅผ ์ง„ํ–‰ํ•œ ํ›„์— ๋‹ค์‹œ ํ• ๋‹นํ•˜์ง€ ์•Š์•˜๋‹ค.
  • ์ „์œ„(prefix) ๋˜๋Š” ํ›„์œ„(postfix)์— ์ฆ๊ฐ ๋˜๋Š” ๊ฐ์†Œ ์—ฐ์‚ฐ์ž๊ฐ€ ์‚ฌ์šฉ๋˜์ง€ ์•Š์•˜๋‹ค.

์ฐธ๊ณ : โ€œJava Docs: 4.12.4. final Variablesโ€

๊ฐ์ฒด์˜ ๊ฒฝ์šฐ์—๋Š” ๊ฐ์ฒด๊ฐ€ ๊ฐ€๋ฆฌํ‚ค๋Š” ์ฐธ์กฐ๋ฅผ ๋ณ€๊ฒฝํ•˜์ง€ ์•Š์œผ๋ฉด ๋œ๋‹ค. ๋”ฐ๋ผ์„œ ์•„๋ž˜์™€ ๊ฐ™์ด ๊ฐ์ฒด์˜ ์ƒํƒœ๋ฅผ ๋ณ€๊ฒฝํ•˜๋”๋ผ๋„ effectively final์ด๋‹ค.

List<Person> personList = List.of(new Person(2), new Person(3));
for (Person p : personList) {
    p.setId(2);
    personList.removeIf(o -> o.getId() == p.getId());
}


Lambda Capturing

๋žŒ๋‹ค์—์„œ๋Š” ์™ธ๋ถ€์— ์ •์˜๋œ ๋ณ€์ˆ˜๋ฅผ ์‚ฌ์šฉํ•  ๋•Œ ๋‚ด๋ถ€์—์„œ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋„๋ก ๋ณต์‚ฌ๋ณธ์„ ์ƒ์„ฑํ•œ๋‹ค. ์ด๋ฅผ ๋žŒ๋‹ค ์บก์ฒ˜๋ง(Lambda Capturing)์ด๋ผ๊ณ  ํ•˜๋Š”๋ฐ ์—ฌ๊ธฐ์„œ ์™ธ๋ถ€ ๋ณ€์ˆ˜๋Š” ์ง€์—ญ ๋ณ€์ˆ˜๋ฅผ ๋น„๋กฏํ•˜์—ฌ ์ธ์Šคํ„ด์Šค ๋ณ€์ˆ˜์™€ ํด๋ž˜์Šค ๋ณ€์ˆ˜๋ฅผ ํฌํ•จํ•œ๋‹ค.

์™ธ๋ถ€ ๋ณ€์ˆ˜๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๋žŒ๋‹ค์‹(Capturing Lambda) ์˜ˆ์ œ๋ฅผ ์‚ดํŽด๋ณด์ž. ์ฒซ ๋ฒˆ์งธ ์˜ˆ์ œ๋Š” ์™ธ๋ถ€์— ์„ ์–ธ๋œ ์ธ์Šคํ„ด์Šค ๋ณ€์ˆ˜๋ฅผ ์ฐธ์กฐํ•˜๊ณ  ๋‘ ๋ฒˆ์งธ ์˜ˆ์ œ๋Š” ๋žŒ๋‹ค ์™ธ๋ถ€์— ์„ ์–ธ๋œ ์ง€์—ญ ๋ณ€์ˆ˜๋ฅผ ์ฐธ์กฐํ•œ๋‹ค.

// Capturing Lambda ์˜ˆ์ œ1: ์™ธ๋ถ€ ์ธ์Šคํ„ด์Šค ๋ณ€์ˆ˜ ์ฐธ์กฐ
public class Tester {
	private int count = 0;

	public void someMethod() {
		Runnable runnable = () -> System.out.println("count: " + count);
	}
}
    
// Capturing Lambda ์˜ˆ์ œ2: ์™ธ๋ถ€ ์ง€์—ญ ๋ณ€์ˆ˜ ์ฐธ์กฐ
public void someMethod() {
    int count = 0;
    Runnable runnable = () -> System.out.println(count);
}

์ด์™€ ๋ฐ˜๋Œ€๋กœ ๋žŒ๋‹ค ๋‚ด๋ถ€์—์„œ ์ ‘๊ทผํ•˜๋Š” ์™ธ๋ถ€ ๋ณ€์ˆ˜๊ฐ€ ์—†๋Š”(Non-Capturing Lambda) ์˜ˆ์ œ๋Š” ์•„๋ž˜์™€ ๊ฐ™๋‹ค.

// Non-Capturing Lambda
Runnable runnable = () -> {
    String msg = "Taengtest";
    System.out.println(msg)
};

// Non-Capturing Lambda
Function<Integer, Integer> func = (param) -> 5 * param;
func.apply(5);


์™œ ๋ณต์‚ฌ๋ณธ์„ ๋งŒ๋“ค๊นŒ?

๊ทธ๋ ‡๋‹ค๋ฉด ๋žŒ๋‹ค์‹ ๋‚ด๋ถ€์—์„œ ์ฐธ์กฐํ•˜๋Š” ์™ธ๋ถ€ ๋ณ€์ˆ˜๋ฅผ ์บก์ฒ˜๋งํ•˜๋Š” ์ด์œ ๋Š” ๋ฌด์—‡์ผ๊นŒ? ์ด๋Š” ์ฐธ์กฐํ•˜๋Š” ์™ธ๋ถ€ ๋ณ€์ˆ˜๊ฐ€ ์ง€์—ญ ๋ณ€์ˆ˜์ผ ๋•Œ ์กฐ๊ธˆ ๋” ๋ช…ํ™•ํ•˜๊ฒŒ ์ดํ•ดํ•  ์ˆ˜ ์žˆ๋‹ค.

์ง€์—ญ ๋ณ€์ˆ˜๋Š” ๋ฉ”๋ชจ๋ฆฌ ์˜์—ญ ์ค‘ ์Šคํƒ(Stack)์— ํ• ๋‹น๋œ๋‹ค. ์Šคํƒ ์˜์—ญ์€ ์Šค๋ ˆ๋“œ๋งˆ๋‹ค ์ž์‹ ๋งŒ์˜ ๊ณ ์œ ํ•œ ์˜์—ญ์„ ๊ฐ–๋Š” ํŠน์„ฑ์„ ๊ฐ–๋Š”๋‹ค. ๋”ฐ๋ผ์„œ ์Šค๋ ˆ๋“œ๋ผ๋ฆฌ ๊ณต์œ ํ•  ์ˆ˜ ์—†์œผ๋ฉฐ ์Šค๋ ˆ๋“œ๊ฐ€ ์ข…๋ฃŒ๋˜๋Š” ๊ฒฝ์šฐ ์ƒ์„ฑ๋œ ์Šคํƒ ์˜์—ญ๋„ ์‚ฌ๋ผ์ง€๊ฒŒ ๋œ๋‹ค. ๋”ฐ๋ผ์„œ ์™ธ๋ถ€ ์ง€์—ญ ๋ณ€์ˆ˜๋ฅผ ๊ทธ๋Œ€๋กœ ์ฐธ์กฐํ•˜์ง€ ๋ชปํ•˜๊ธฐ ๋•Œ๋ฌธ์— ๋ณต์‚ฌ๋ณธ์„ ์ƒ์„ฑํ•˜๋Š” ๊ฒƒ์ด๋‹ค.

๋งŒ์•ฝ์— ๋ณต์‚ฌ๋ณธ์„ ๋งŒ๋“ค์ง€ ์•Š๋Š” ๊ฒฝ์šฐ๋Š” ์–ด๋–ป๊ฒŒ ๋ ๊นŒ? ์•„๋ž˜ ์ฝ”๋“œ๋Š” ์ •์ƒ์ ์œผ๋กœ ์ปดํŒŒ์ผ ๋˜๋Š” ์ฝ”๋“œ์ง€๋งŒ ๊ธฐ์กด์˜ ์ž๋ฐ” ์ŠคํŽ™๊ณผ๋Š” ๋‹ค๋ฅด๊ฒŒ ์™ธ๋ถ€ ์ง€์—ญ ๋ณ€์ˆ˜๋ฅผ ์บก์ฒ˜๋งํ•˜์ง€ ์•Š๋Š”๋‹ค๊ณ  ๊ฐ€์ •ํ•ด๋ณด์ž.

public void test() {
    // local variable
    int count = 0;

    new Thread(() -> {
        try {
        	// `count` ๋ฅผ ๋ณต์‚ฌํ•˜์ง€ ์•Š๋Š”๋‹ค๊ณ  ๊ฐ€์ •
            Thread.sleep(1000);
            System.out.println("count :" + count);
        } catch (InterruptedException e) {
            // Exception Handling
        }
    }).start();
    
    System.out.println("count :" + count);
}

์œ„ ์ฝ”๋“œ๊ฐ€ ์ •์ƒ ๋™์ž‘ํ•œ๋‹ค๋ฉด ์–ด๋–ป๊ฒŒ ๋ ๊นŒ? ์˜ˆ์ œ์ฒ˜๋Ÿผ ๋žŒ๋‹ค๋Š” ๋ณ„๋„์˜ ์Šค๋ ˆ๋“œ์—์„œ ์ˆ˜ํ–‰๋  ์ˆ˜ ์žˆ๋‹ค. ๋˜ํ•œ ์•ž์„œ ์„ค๋ช…ํ•œ ๊ฒƒ์ฒ˜๋Ÿผ ๊ฐ ์Šค๋ ˆ๋“œ๋งˆ๋‹ค ๊ณ ์œ ํ•œ ์Šคํƒ ์˜์—ญ์„ ๊ฐ€์ง€๋ฉฐ, ์ง€์—ญ ๋ณ€์ˆ˜๋Š” ์Šคํƒ ์˜์—ญ์— ํ• ๋‹น๋œ๋‹ค.

๋”ฐ๋ผ์„œ test ๋ฉ”์„œ๋“œ๋ฅผ ์‹คํ–‰ํ•˜๋Š” ์Šค๋ ˆ๋“œ๋Š” ๋žŒ๋‹ค์‹์„ ์‹คํ–‰ํ•˜๋Š” ์Šค๋ ˆ๋“œ๊ฐ€ ๋๋‚˜๊ธฐ๋„ ์ „์— ์Šคํƒ ์˜์—ญ์—์„œ ์‚ฌ๋ผ์งˆ ์ˆ˜ ์žˆ๋‹ค. ์ฆ‰, ๋žŒ๋‹ค ๋‚ด๋ถ€์—์„œ ๋ฉ”์„œ๋“œ์— ์„ ์–ธ๋œ ์ง€์—ญ ๋ณ€์ˆ˜์ธ count๋ฅผ ์ฐธ์กฐํ•˜์ง€ ๋ชปํ•˜๋Š” ๊ฒฝ์šฐ๊ฐ€ ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ๋‹ค.


์™œ ๋žŒ๋‹ค์—์„œ ์™ธ๋ถ€ ์ง€์—ญ ๋ณ€์ˆ˜์˜ ๊ฐ’์„ ๋ณ€๊ฒฝํ•  ์ˆ˜ ์—†์„๊นŒ?

๊ทธ๋ ‡๋‹ค๋ฉด ๋žŒ๋‹ค ๋‚ด๋ถ€์—์„œ ์™ธ๋ถ€ ์ง€์—ญ ๋ณ€์ˆ˜์˜ ๊ฐ’์„ ๋ณ€๊ฒฝํ•˜๋ ค๊ณ  ํ•˜๋ฉด ์ปดํŒŒ์ผ ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ•˜๋Š” ์ด์œ ๋Š” ๋ฌด์—‡์ผ๊นŒ? โ€œ๋ณต์‚ฌ๋ณธ์„ ์ƒ์„ฑํ•œ๋‹ค๋ฉด, ๊ฐ’์„ ๋ณ€๊ฒฝํ•ด๋„ ๊ดœ์ฐฎ์ง€ ์•Š์„๊นŒ?โ€๋ผ๊ณ  ์ƒ๊ฐํ•  ์ˆ˜๋„ ์žˆ๋‹ค.

๋žŒ๋‹ค์‹์€ ์•ž์„œ ์‚ดํŽด๋ณธ ๊ฒƒ์ฒ˜๋Ÿผ ๋ณ„๋„ ์Šค๋ ˆ๋“œ์—์„œ ์ˆ˜ํ–‰์ด ๊ฐ€๋Šฅํ•˜๋‹ค. ๊ทธ๋ ‡๊ธฐ ๋•Œ๋ฌธ์— ์™ธ๋ถ€ ์ง€์—ญ ๋ณ€์ˆ˜๋ฅผ ์ œ์–ดํ•˜๋Š” ์Šค๋ ˆ๋“œ์™€ ๋žŒ๋‹ค์‹์„ ์ˆ˜ํ–‰ํ•˜๋Š” ์Šค๋ ˆ๋“œ๊ฐ€ ์„œ๋กœ ๋‹ค๋ฅผ ์ˆ˜ ์žˆ๋‹ค.

๋˜ ๋‹ค๋ฅธ ์˜ˆ์ œ๋ฅผ ์‚ดํŽด๋ณด์ž. ๋‹ค๋งŒ ์ด๋ฒˆ ์˜ˆ์ œ ์ฝ”๋“œ๋Š” ์ปดํŒŒ์ผ ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ•œ๋‹ค. ํ•˜์ง€๋งŒ ์™ธ๋ถ€ ์ง€์—ญ ๋ณ€์ˆ˜์˜ ๊ฐ’์„ ๋ณ€๊ฒฝํ•˜๋ฉด ์•ˆ ๋˜๋Š” ์ด์œ ๋ฅผ ์ดํ•ดํ•˜๊ธฐ ์œ„ํ•ด ์ •์ƒ์ ์œผ๋กœ ์‹คํ–‰๋œ๋‹ค๊ณ  ๊ฐ€์ •ํ•ด๋ณด์ž. ์•„๋ž˜ ์ฝ”๋“œ๊ฐ€ ์ •์ƒ์ ์œผ๋กœ ์ปดํŒŒ์ผ ๋˜๊ณ  ์‹คํ–‰๋  ๋•Œ์˜ ๋ฌธ์ œ๋Š” ๋ฌด์—‡์ผ๊นŒ?

public class Tester {

	ExecutorService executor = Executors.newFixedThreadPool(1);

	public void testMultiThreading() {
		// ์Šค๋ ˆ๋“œ A
		boolean doLoop = true;

		executor.execute(() -> {
			// ์Šค๋ ˆ๋“œ B
			while (doLoop) {
				// something to do
			}
		});
		doLoop = false;
	}
}

์œ„ ์˜ˆ์ œ์—์„œ๋Š” ๋‘ ๊ฐœ์˜ ์Šค๋ ˆ๋“œ๊ฐ€ ์กด์žฌํ•˜๋Š”๋ฐ, ํ•˜๋‚˜๋Š” ์ง€์—ญ ๋ณ€์ˆ˜๋ฅผ ์ œ์–ดํ•˜๋Š” ์Šค๋ ˆ๋“œ์ด๊ณ  ๋‹ค๋ฅธ ํ•˜๋‚˜๋Š” ๋žŒ๋‹ค์‹์„ ์‹คํ–‰ํ•˜๋Š” ์Šค๋ ˆ๋“œ๋‹ค. ๊ทธ๋ฆฌ๊ณ  ์•ž์„œ ์„ค๋ช…ํ•œ ๊ฒƒ์ฒ˜๋Ÿผ ๋žŒ๋‹ค์—์„œ๋Š” ์™ธ๋ถ€ ์ง€์—ญ ๋ณ€์ˆ˜๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒฝ์šฐ ์บก์ฒ˜๋ง์„ ํ•˜๊ฒŒ ๋˜๊ธฐ ๋•Œ๋ฌธ์— ๋žŒ๋‹ค์‹์„ ์‹คํ–‰ํ•˜๋Š” ์Šค๋ ˆ๋“œ์—์„œ๋Š” ์ง€์—ญ ๋ณ€์ˆ˜ doLoop์˜ ๊ฐ’์„ ์ฐธ์กฐํ•˜๊ธฐ ์œ„ํ•ด ์ด๋ฅผ ๋ณต์‚ฌํ•œ๋‹ค.

๋ฌธ์ œ๋Š” ์ด ๋ถ€๋ถ„์—์„œ ๋ฐœ์ƒํ•œ๋‹ค. ๋ณต์‚ฌ๋˜๋Š” ๊ฐ’์ธ ์™ธ๋ถ€ ์ง€์—ญ ๋ณ€์ˆ˜๊ฐ€ ๋ณ€๊ฒฝ ๊ฐ€๋Šฅํ•˜๊ฒŒ ๋˜๋Š” ๊ฒฝ์šฐ ๋ณต์‚ฌ๋œ ๊ฐ’์ด ์ตœ์‹  ๊ฐ’์ž„์„ ๋ณด์žฅํ•  ์ˆ˜ ์—†๋‹ค. ์ด๋Š” ๋ณ€์ˆ˜์˜ ๊ฐ€์‹œ์„ฑ(visibility)๊ณผ๋„ ์—ฐ๊ด€์ด ์žˆ๋Š”๋ฐ, ์Šคํƒ ์˜์—ญ์€ ์Šค๋ ˆ๋“œ๋งˆ๋‹ค ์ƒ์„ฑ๋˜๊ธฐ ๋•Œ๋ฌธ์— ์Šค๋ ˆ๋“œ A, B๊ฐ€ ๊ฐ–๋Š” ์Šคํƒ ์˜์—ญ์€ ๊ฐ์ž ๊ณ ์œ ํ•˜๋‹ค. ๋”ฐ๋ผ์„œ ํ•œ ์Šค๋ ˆ๋“œ์—์„œ ๋‹ค๋ฅธ ์Šค๋ ˆ๋“œ์˜ ์Šคํƒ์— ์žˆ๋Š” ๊ฐ’์˜ ๋ณ€๊ฒฝ์‚ฌํ•ญ์„ ํ™•์ธํ•  ์ˆ˜๊ฐ€ ์—†๋‹ค.

๋”ฐ๋ผ์„œ ์œ„์™€ ๊ฐ™์€ ์˜ˆ์ œ๊ฐ€ ์ •์ƒ์ ์œผ๋กœ ์ปดํŒŒ์ผ๋˜๊ณ  ์‹คํ–‰๋œ๋‹ค๋ฉด ๋ณต์‚ฌ๋œ ๊ฐ’์„ ๋ณด์žฅํ•  ์ˆ˜ ์—†์œผ๋ฏ€๋กœ ๋™์‹œ์„ฑ ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ•˜์—ฌ ๊ฒฐ๊ณผ๋ฅผ ์˜ˆ์ธกํ•  ์ˆ˜ ์—†๋Š” ์ƒํ™ฉ์ด ๋ฐœ์ƒํ•œ๋‹ค. ์ด๊ฒƒ์ด ๋žŒ๋‹ค์‹์—์„œ ์ฐธ์กฐํ•˜๋Š” ์™ธ๋ถ€ ์ง€์—ญ ๋ณ€์ˆ˜๊ฐ€ ๊ฐ’์ด ๋ณ€๊ฒฝ๋˜์ง€ ์•Š์•„์•ผ ํ•˜๋Š” ์ด์œ ๋‹ค.


๊ทธ๋ ‡๋‹ค๋ฉด ์ธ์Šคํ„ด์Šค ๋ณ€์ˆ˜์™€ ํด๋ž˜์Šค ๋ณ€์ˆ˜๋Š”?

๋จผ์ € ์ธ์Šคํ„ด์Šค ๋ณ€์ˆ˜์™€ ํด๋ž˜์Šค ๋ณ€์ˆ˜๊ฐ€ ๋ฌด์—‡์ธ์ง€ ์ด๋“ค์˜ ์ •์˜์— ๋Œ€ํ•ด์„œ ์•Œ์•„๋ณด์ž.

์ธ์Šคํ„ด์Šค ๋ณ€์ˆ˜๋Š” ํด๋ž˜์Šค์— ์„ ์–ธ๋œ ๋ณ€์ˆ˜๋ฅผ ๋งํ•˜๋ฉฐ ์ธ์Šคํ„ด์Šค ์ •๋ณด๋ฅผ ๋‹ด๊ณ  ์žˆ๋Š” ํž™(heap) ์˜์—ญ์— ํ• ๋‹น๋œ๋‹ค. ๊ทธ๋ฆฌ๊ณ  ํด๋ž˜์Šค ๋ณ€์ˆ˜๋Š” ํด๋ž˜์Šค์— ์„ ์–ธ๋œ static ๋ณ€์ˆ˜๋ฅผ ๋งํ•˜๋ฉฐ ์ธ์Šคํ„ด์Šค ์ƒ์„ฑ ์—†์ด ๋ฐ”๋กœ ์ƒ์„ฑ๋˜๋ฉฐ ๋ฉ”์„œ๋“œ(method) ์˜์—ญ์— ์„ ์–ธ๋œ๋‹ค.

๊ทธ๋ ‡๊ธฐ ๋•Œ๋ฌธ์— ํ• ๋‹น๋œ ๋ฉ”๋ชจ๋ฆฌ ์˜์—ญ์ด ์ง€์—ญ ๋ณ€์ˆ˜๊ฐ€ ํ• ๋‹น๋˜๋Š” ์Šคํƒ ์˜์—ญ๊ณผ ๋‹ค๋ฅด๊ฒŒ ๋ฐ”๋กœ ํšŒ์ˆ˜๋˜์ง€ ์•Š์•„ ๋ณต์‚ฌํ•˜๋Š” ๊ณผ์ •์ด ๋ถˆํ•„์š”ํ•˜๋‹ค. ๋”ฐ๋ผ์„œ ์•„๋ž˜์™€ ๊ฐ™์€ ์ฝ”๋“œ๋Š” ์ •์ƒ์ ์œผ๋กœ ์ปดํŒŒ์ผ ๋œ๋‹ค.

public class Tester {
    private int instanceVariable = 0;
	private static int staticVariable = 0;

	public void someMethodWithStaticVariable() {
		instanceVariable = 1;
		Runnable runnable = () -> {
			instanceVariable++;
		};
	}

	public void someMethodWithInstanceVariable() {
		staticVariable = 1;
		Runnable runnable = () -> {
			staticVariable++;
		};
	}
}


์ •๋ฆฌํ•˜๋ฉด

๋žŒ๋‹ค์‹ ๋‚ด๋ถ€์—์„œ ์™ธ๋ถ€ ์ง€์—ญ ๋ณ€์ˆ˜๋ฅผ ์ฐธ์กฐํ•˜๋Š” ๊ฒฝ์šฐ final ๋˜๋Š” effectively final์ด์–ด์•ผ ํ•œ๋‹ค. ์ด๋Ÿฌํ•œ ์ด์œ ๋Š” ์ง€์—ญ ๋ณ€์ˆ˜๊ฐ€ ๋ฉ”๋ชจ๋ฆฌ ์˜์—ญ์ค‘ ์Šคํƒ(Stack) ์˜์—ญ์— ํ• ๋‹น๋˜๋Š” ๊ฒƒ๊ณผ ๊ด€๋ จ์ด ์žˆ๋‹ค.

์Šคํƒ ์˜์—ญ์€ ์Šค๋ ˆ๋“œ ๋ณ„๋กœ ๊ณ ์œ ํ•˜๊ธฐ ๋•Œ๋ฌธ์— ์ง€์—ญ ๋ณ€์ˆ˜๊ฐ€ ํ• ๋‹น๋œ ์Šค๋ ˆ๋“œ๊ฐ€ ์ข…๋ฃŒ๋˜๋ฉด ์ง€์—ญ ๋ณ€์ˆ˜๋ฅผ ๋”์ด์ƒ ์ฐธ์กฐํ•˜์ง€ ๋ชปํ•˜๊ฒŒ ๋œ๋‹ค. ๋”ฐ๋ผ์„œ ๋ณ„๋„ ์Šค๋ ˆ๋“œ์—์„œ ์‹คํ–‰ ๊ฐ€๋Šฅํ•œ ๋žŒ๋‹ค์—์„œ๋Š” ์™ธ๋ถ€ ์ง€์—ญ ๋ณ€์ˆ˜๋ฅผ ๋ณต์‚ฌํ•˜๋Š” ๊ณผ์ •์„ ๊ฑฐ์น˜๋Š”๋ฐ, ๋ณต์‚ฌ๋˜๋Š” ๊ฐ’์ด ๋ณ€๊ฒฝ ๊ฐ€๋Šฅํ•˜๋‹ค๋ฉด ์ฐธ์กฐํ•˜๋Š” ๋ณ€์ˆ˜์˜ ์ตœ์‹ ๊ฐ’์„ ๋ณด์žฅํ•  ์ˆ˜ ์—†์–ด ๋ฉ€ํ‹ฐ ์Šค๋ ˆ๋“œ ํ™˜๊ฒฝ์—์„œ ๋™์‹œ์„ฑ ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ๋‹ค.

๋”ฐ๋ผ์„œ, ๋žŒ๋‹ค ๋‚ด๋ถ€์—์„œ ์™ธ๋ถ€ ์ง€์—ญ ๋ณ€์ˆ˜๋ฅผ ์ฐธ์กฐํ•  ๋•Œ๋Š” ๋ฐ˜๋“œ์‹œ fianl ๋˜๋Š” effectively final์ด์–ด์•ผ ํ•œ๋‹ค.