본문 바로가기
언어

[Java] Java8 - 함수형 프로그래밍 (4)

by 코린이 프로도 2022. 12. 1.
반응형

Java 8 시리즈는 인프런 강의를 듣고 정리한 내용이다.

참고 : https://www.inflearn.com/course/the-java-java8/dashboard

 

더 자바, Java 8 - 인프런 | 강의

자바 8에 추가된 기능들은 자바가 제공하는 API는 물론이고 스프링 같은 제 3의 라이브러리 및 프레임워크에서도 널리 사용되고 있습니다. 이 시대의 자바 개발자라면 반드시 알아야 합니다. 이

www.inflearn.com

람다 표현식

public class Cal {
	public static void main(String[] args) {
    	UnaryOperator<Integer> plus10 = (i) -> i+10;
        UnaryOperator<Integer> multiply = (i) -> i*2;
        UnaryOperator<Integer> plus5 = (i) -> {
        	return i+5;
        };
        System.out.println(plus10.andThen(multiply).apply(2));
    }
}

위는 람다 표현식을 활용한 소스코드다.

i는 '매개변수'를 나타내고 매개변수의 타입으로는 UnaryOperator에 Integer로 정의되어 있어 생략이 가능하다.

매개변수가 있을 경우에는 위 i처럼 변수명을 넣어주면 되지만 만약 없을 경우 Supplier와 같이 ()만 표시하면 된다.

다음은 화살표 오른쪽 부분은 매개변수를 활용한 메소드의 동작을 정의하는 '바디'이다. 

한 줄로 표현할 때는 괄호와 return을 생략해도 된다. 두 줄 이상일 경우 메소드 정의 방식처럼 화살표 다음으로 괄호를 열고 동작 방식을 정의해주고 괄호를 닫고 세미 콜론으로 마무리하면 된다. 

 

변수 캡처

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(10);
    }
    
    private void oudated_java_run() {
    	final int baseNumber = 10; //final 생략 가능 java8 부터
        
        // 로컬 클래스
        class LocalClass {
        	void printBaseNumber() {
            	System.out.println(baseNumber);
            }
        }
        
        // 익명 클래스
        Consumer<Integer> integerConsumer = new Consumer<Integer>() {
        	@Override
            public void accept(Integer integer) {
            	System.out.println(baseNumber);
            }
        }
    }
}

 위와 같이 지역변수(Local variable)로 baseNumber를 선언하면 변수 캡처가 된다. 이 기능은 기존에 내부 클래스와 익명 클래스에서도 쓰이던 기능이다. 캡처가 되면 람다 바디에서 해당 변수를 참조할 수 있게 된다.

 java 8 이전에는 final과 함께 지역변수를 선언해야 했지만 java8부터는 final을 생략하더라도 final의 역할을 한다. 즉 변수의 값을 변경할 수 없다. 이를 effective final이라고 한다. 같은 스코프 내에서 변경하고 참조하려고 하면 인텔리제이에서 컴파일 에러로 빨간줄이 뜨는 것을 볼 수 있다.

 

 여기서 중요한 점으로 람다와 나머지 둘의 차이점은 바로 쉐도잉이다.

쉐도잉이란 바깥 scope에서 선언한 변수를 좀 더 작은 scope에서 다시 선언하면 가려지는 것을 말한다.

이 쉐도잉이 람다에는 적용되지 않는다. 왜냐하면 람다의 바디의 scope는 바깥의 메소드 scope과 같은 것으로 취급하기 때문이다. 같은 scope에서 똑같은 변수를 두 개 선언하면 안 되는 원리와 같다.

 

쉽게 소스코드를 살펴보자.

public class Foo {
	public static void main(String[] args) {
    	Foo foo = new Foo();
        foo.run();
    }
    
    private void run() {
    	int baseNumber = 10;
        // 람다
    	IntConsumer printInt = (i) -> {
        	// 여기서 아래와 같이 baseNumber를 또 선언하는 것이 불가능하다.
            // int baseNumber = 5;
            // i 대신 baseNumber로 선언하는 것도 불가능하다. 쉐도잉이 안 되기 때문
        	System.out.println(i + baseNumber);
        };
        
       	printInt.accept(10);
    }
    
    private void oudated_java_run() {
    	final int baseNumber = 10; //final 생략 가능 java8 부터
        
        // 로컬 클래스
        class LocalClass {
        	void printBaseNumber() {
            	int baseNumber = 20; 
            	System.out.println(baseNumber); //20이 출력되는 것이 바로 쉐도잉
            }
        }
        
        // 익명 클래스
        Consumer<Integer> integerConsumer = new Consumer<Integer>() {
        
        	// integer 변수명을 baseNumber로 바꿔도 동작하는 것이 바로 쉐도잉
        	@Override
            public void accept(Integer integer) {
            	System.out.println(baseNumber);
            }
        }
    }
}

 

반응형

'언어' 카테고리의 다른 글

[Java] static  (0) 2022.12.17
[Java] Java8 - 함수형 프로그래밍(5)  (0) 2022.12.04
컴파일 언어 vs 인터프리터 언어  (0) 2022.11.29
[Java] 다형성 Ploymorphism  (0) 2022.11.08
[Java] Java8 - 함수형 프로그래밍 (3)  (0) 2022.10.22