Study_The JAVA 8_3

dragon9265·2022년 1월 26일
0

스터디

목록 보기
13/23
post-thumbnail

자바 기초 스터디_22.01.26(수)


람다 표현식

람다 표현식 구성


public class Foo {
	public static void main(String[] args) {
    		UnaryOperator<Integer> plus10 = (i) -> i + 10; // 인자(i) -> 바디(i+10)
            	System.out.println(plus10.apply(1));  // 11 출력
    	}
}	
  • (인자 리스트) -> {바디}로 구성되어 있다.
  • 바디가 한줄이면 생략하여 위처럼 한줄로 작성할 수 있다.
    - 📖 인자 리스트 종류
    - 인자가 없을 때 : () -> {바디} // 인자를 안받는 Supplier 함수 인터페이스가 대표적인 예다.
    - 인자가 한개일 때 : (i) or i
    - 인자가 여러개 일 때 : (i,j)
    - ❗️인자의 타입은 컴파일러가 추론가능하여 생략도 되므로 선택에 맞게 명시 or 생략 하면된다.

변수 캡쳐(Variable Capture)

로컬 변수 캡쳐


import java.util.function.*;

public class Foo {
	public static void main(String[] args) {
    		Foo foo = new Foo();
            	foo.run();
    	}
        
        private void run() {
        	int baseNumber = 10; // 사실상 Final인 변수(effective final)
            
            	IntConsumer printInt = (i) -> {
                 	System.out.println(i + baseNumber);
               	};
                
                printInt.accept(10);
       	}
}	
  • 람다 바디에서는 파라미터외에 바디{} 외부에 있는 변수를 참조할 수 있는데,
    이런 행위를 람다 캡쳐링(Lamda Capturing) 혹은 로컬 변수 캡쳐라고 부른다.
  • 캡쳐가 가능하기 위해서는, 위 예시의 baseNumber가 Final로 명시되어 있거나
    effective final(사실상 변하지 않아 final과 같은 성격을 지닌 변수)인 경우에만 가능하다.
  • ❗️ Java 8 이전에는 항상 반드시 final이 붙어있어야 했다.
  • ❗️ effective final은 익명 클래스 구현체 또는 람다에서 참조할 수 있는 공통점이 있지만,
    람다는 익명 클래스 구현체와 달리 쉐도잉하지 않는다.

쉐도잉

  • 함수밖의 함수가 가려지는것을 말한다.
  • 로컬클래스, 익명클래스, 람다클래스의 스코프에 따라 쉐도잉 범위가 달라진다.

import java.util.function.*;

public class Foo {
	public static void main(String[] args) {
    		Foo foo = new Foo();
            	foo.run();
    	}
        
        private void run() {
        	int baseNumber = 10; // 사실상 Final인 변수(effective final)
            
            //로컬 클래스
            Class LocalClass {
            	void printBaseNumber() {
                	System.out.println(baseNumber);
                }
            }
                                    
            //익명 클래스
            Consumer<Integer> integerConsumer = new Consumer() {
            	@Override
                public void accpet(Integer integer) {
                	System.out.println(baseNumber);
                }
            };
            
            
            //람다
            IntConsumer printInt = (i) -> {
               	System.out.println(i + baseNumber);
            };
                
            printInt.accept(10);
       	}
}	

  • 위 예제를 통해 클래스별 쉐도잉을 그림으로 나타내보면 하기와 같다.

로컬클래스, 익명클래스


import java.util.function.*;

public class Foo {
	public static void main(String[] args) {
    		Foo foo = new Foo();
            	foo.run();
    	}
        
        private void run() {
        	int baseNumber = 10; // 사실상 Final인 변수(effective final)
            
            //로컬클래스
            Class LocalClass { // 로컬클래스의 Scope 범위 시작
            	void printBaseNumber() {
                	int baseNumber = 11; //참조하고있는 외부 변수와 동일한 변수명을 스코프 내에서 재정의
                	System.out.println(baseNumber); // 10이 아닌 11이 출력된다.
                }
            } // 로컬클래스의 Scope 범위 끝
                                    
            //익명클래스
            Consumer<Integer> integerConsumer = new Consumer() { // 익명클래스의 Scope 범위 시작
            	@Override
                public void accpet(Integer baseNumber) { // 파라미터 이름을 참조하고 있는 외부 변수와 동일한 이름으로 변경
                	System.out.println(baseNumber);
                }
            }; // 익명클래스의 Scope 범위 끝
            
  	    printInt.accept(10);
       	}
}	

  • 그림과 같이 로컬클래스와 익명클래스는 자신의 스코프 안에서 외부 참조하고 있는
    변수명과 동일한 변수명으로 재정의 하게 되면,자신의 스코프 내부의 재정의한
    변수가 외부 참조하고 있던 변수명을 가려버린다.

람다


import java.util.function.*;

public class Foo {
	public static void main(String[] args) {
    		Foo foo = new Foo();
            	foo.run();
    	}
        
        private void run() { // 람다의 Scope 범위 시작
            	int baseNumber = 10; // 사실상 Final인 변수(effective final)
              
           	//람다
            	IntConsumer printInt = (baseNumber) -> { // 같은 변수명을 사용할 경우 컴파일 에러가 난다.
          	     	System.out.println(baseNumber);
          	};
               
          	printInt.accept(10);
       	} // 람다의 Scope 범위 끝
}	

  • 사실상 람다의 스코프 범위는 외부 메소드의 범위와 같으므로 동일한 변수명을 2개 못쓰는것이다.

    왜?? 다르지
    익명클래스는 익명 "객체"로 볼 수 있지만, 람다는 객체가 아니여서 그렇다.
    즉, 익명클래스 내에서 this는 자기 자신을 가리키지만 람다에서의 this는 자신을 선언한 클래스를 말한다.

profile
코딩도 점진적 과부화

0개의 댓글