Java의 람다

혜삐·2023년 8월 9일
0

톺아보기

목록 보기
17/21

javaScript를 공부하다보면 람다 표현식이라는 것을 배우게 된다.
javaScript에서는 람다 함수를 화살표 함수라고 부른다.

// 일반 함수

function printHello(){
	console.log('Hello');
}

// 화살표 함수

const printHello = () => console.log('Hello');

그런데 Java에도 람다가 있다는 것을 알게 되었다.

형태는 JS와 매우 비슷하다.

	IntConsumer printInt = (i) -> {
		System.out.println(i + baseNumber);
	};

똑같이 화살표를 쓴다.
바디는 화살표의 오른똑에 함수 본문을 정의하고, 여러 줄인 경우에 {}를 사용해서 묶는다. 또한 한 줄이라면 생략도 가능하고, return 도 생략 가능하다.

변수 캡쳐

람다의 큰 특징 중 하나는 변수 캡쳐이다.
람다의 바디에서 지역 변수를 사용하게 되면 해당 지역 변수가 사용된다.

람다를 감싸고 있는 영역의 지역 변수

package Foo;

import java.util.function.Consumer;
import java.util.function.IntConsumer;

public class Foo {
	public static void main(String[] args) {
		Foo foo = new Foo();
		foo.run();
	}
	
	private void run() {
		int baseNumber= 10;
		
		IntConsumer printInt = (i) -> {
			System.out.println(i + baseNumber);
		};
		
		printInt.accept(2);
	}
}

이 경우 baseNumber는 람다를 감싸고 있는 run() 의 지역변수인 baseNumber이다. 단 이 때, baseNumber가 final이 아니라면 불가하다.

그럼 위 경우에는 final이라고 선언하지 않았는데 왜 가능할까?
선언하지 않았어도 effective final(사실상의 final , 변수 선언 후 수정 안 하는 경우)라면 가능하다.

람다와 익명 클래스, 내부 클래스 모두 final 지역 변수를 참조 할 수 있다.

package Foo;

import java.util.function.Consumer;
import java.util.function.IntConsumer;

public class Foo {
	public static void main(String[] args) {
		Foo foo = new Foo();
		foo.run();
	}
	
	private void run() {
		int baseNumber= 10;
		
		class LocalClass {
			void printBaseNumber() {
				System.out.println(baseNumber);
			}
		};
		
		Consumer<Integer> integerConsumer = new Consumer<Integer> () {
			public void accept(Integer integer) {
				System.out.println(baseNumber);
			}
		};
		
		IntConsumer printInt = (i) -> {
			System.out.println(i + baseNumber);
		};
		
		
		LocalClass lc = new LocalClass();
		lc.printBaseNumber();
		printInt.accept(2);
		integerConsumer.accept(2);
	}
}

이 경우 모두 baseNumber를 참조할 수 있다.
그렇지만 매우 큰 차이가 있다.

Shadowing

익명클래스, 내부클래스 와 람다의 차이점은 바로 Shadowing이다.

Untitled

람다는 익명 클래스 구현체와 달리 ‘쉐도윙’하지 않는다.
익명 클래스는 새로 스콥을 만들지만, 람다는 람다를 감싸고 있는 스콥과 같다.
익명 클래스와 로컬 클래스는 또 다른 스콥이므로 쉐도잉이 일어나지만, 람다는 감싸고 있는 것(여기서는 run)과 같은 스콥을 갖는다.

package Foo;

import java.util.function.Consumer;
import java.util.function.IntConsumer;

public class Foo {
	public static void main(String[] args) {
		Foo foo = new Foo();
		foo.run();
	}
	
	private void run() {
		int baseNumber= 10;
		
		class LocalClass {
			void printBaseNumber() {
				int baseNumber = 11;
				System.out.println(baseNumber); // 11
			}
		};
		
		Consumer<Integer> integerConsumer = new Consumer<Integer> () {
			public void accept(Integer baseNumber) {
				System.out.println(baseNumber); // 2
			}
		};
		
		IntConsumer printInt = (baseNumber) -> {
			System.out.println(i + baseNumber); // 안됨!!
		};
		
		
		
		LocalClass lc = new LocalClass();
		lc.printBaseNumber();
		integerConsumer.accept(2);
		printInt.accept(2);
	}
}

위의 경우를 보면 내부 클래스와 익명 클래스는 각자의 scope을 가지므로 baseNumber를 지역 변수로 선언할 수 있다.
그렇지만 람다의 경우 run() 과 같은 scope를 가지므로 같은 변수를 또 선언할 수 없어서 에러가 발생한다.

출처

profile
혜삐월드

0개의 댓글