You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Runnable 인터페이스의 유일한 메서드 abstractMethod는 파라미터와 반환값이 없으므로
Runnable 인터페이스는 인수와 반환값이 없는 시그니처라고 생각할 수 있다.
=> 파라미터를 받고 리턴을 명시하는 메서드가 함수 디스크립터다.
(Apple, Apple) -> int//2개의 Apple을 인수로 받아 int를 반환하는 하는 함수를 가르친다.//이것이 함수 디스크립터
람다 활용
//BufferedReader를 사용해서 파일을 읽고 파일에 있는 문구를 출력하는 프로그램//실행 어라운드 패턴//실제 자원을 처리하는 코드를 설정과 정리 두 과정이 둘러싸는 형태publicstaticStringprocessFile() throwsFileNotFoundException, IOException {
try(BufferedReaderbr = newBufferedReader(newFileReader("data.txt"))){
returnbr.readLine(); //실제 필요한 작업을 하는 행
}
}
현재 코드는 파일에서 한 번에 한 줄만 읽을 수 있다.(br.readLine())
그렇다면 한 번에 두 줄을 읽게 하려면 어떻게 해야될까?
여기서 우리가 실제로 필요한 작업을 하는 곳은 br.readLine()임으로 try-catch문은 껍데기로 볼 수 있다.
그래서 훨씬 간결한 람다식을 사용해서 실제 필요한 작업을 파라미터로 전달하면
(Apple apple) -> apple.getWeight() > 150는 Predicate를 의미한다. -> 이것이 target type
Predicate는 test라는 1개의 추상 메서드를 정의하는 함수형 인터페이스
test 메서드는 Apple을 받아 boolean을 리턴하는 함수 디스크립터
filter 메서드로 전달된 인수는 이와 같은 요구사항을 만족해야 함.
위 예제에서 람다 표현식은 Apple을 인수로 받아 boolean을 리턴하기 때문에 유효한 코드다.
같은 람다, 다른 함수형 인터페이스
동일한 람다 표현식이더라도 호환되는 추상 메서드를 가진 함수형 인터페이스가 여러 개 일수 있다.
Callable,PrivilegedAction 인터페이스는 모두 인수를 받지 않으며 제네릭 형식 T를 반환하는 디스크럽터를 가지고 있다.
Callable<Integer> c = () -> 42;
PrivilegedAction<Integer> p = () -> 42;
위와 같은 경우 context 추론에 의해
첫번째 줄의 target type은 Callable이고
두번째 줄의 target type은 PrivilegedAction
인 것을 추론할 수 있다.
특별한 void 호환규칙
람다의 바디에 일반 표현식이 있으면 void를 반환하는 함수 디스크립터와 호환된다.
예를 들어 Consumer context(T -> void)가 기대하는 void 대신 boolean을 반환해도 유효한 코드. Consumer b = s -> list.add(s);
만약 변환하는 타입도 같고, Target type, 함수 디스크립터 마저도 동일하다면 어떤 함수형 인터페이스를 가리키는지 명확하지 않게 된다.
그럴 땐, 캐스트를 해서 명확하게 함수형 인터페이스를 지정해주면 된다.
publicclassCastExample {
publicstaticvoidmain(String[] args) {
// 제곱 계산 함수//Function는 입력과 출력이 모두 Integer인 함수를 나타내는 함수형 인터페이스. //람다 표현식 number -> number * number는 number를 입력으로 받아서 제곱을 계산하고, 결과를 int로 반환. //함수 디스크립터가 동일하지만 타입이 일치하지 않는 상황이 발생.//Function으로 캐스트로 해결Function<Integer, Integer> square = (Function<Integer, Integer>) number -> number * number;
// 함수를 사용하여 제곱 계산Integerresult = square.apply(5);
System.out.println("Result: " + result);
}
}
형식 추론
자바 컴파일러는 람다 표현식이 사용된 context를 이용해서 람다 표현식과 관련된 함수형 인터페이스를 추론한다.
함수 디스크립터를 알 수 있기 때문에 람다의 시그니처도 추론이 가능하다.
그래서 자바 컴파일러는 람다 표현식의 파라미터 형식을 추론할 수 있으므로 파라미터의 Type을 명시적으로 지정하지 않아도 된다.
//형식을 추론하지 않음publicclassNonInferenceExample {
publicstaticvoidmain(String[] args) {
// 문자열을 정수로 변환하는 함수Function<String, Integer> parseToInt = (Stringstr) -> Integer.parseInt(str);
// 함수를 사용하여 문자열을 정수로 변환Integernumber = parseToInt.apply("42");
System.out.println("Number: " + number);
}
}
// 파라미터 str의 타입을 명시적으로 지정. //이 경우에는 형식 추론이 발생하지 않는다.// Function<String, Integer>에 따라 String 타입의 파라미터를 받고 Integer 타입을 반환하는 함수를 나타냄.//형식을 추론함publicclassInferenceExample {
publicstaticvoidmain(String[] args) {
// 문자열을 대문자로 변환하는 함수Function<String, String> toUpperCase = str -> str.toUpperCase();
// 함수를 사용하여 문자열 변환Stringresult = toUpperCase.apply("hello");
System.out.println("Result: " + result);
}
}
//toUpperCase 함수의 람다 표현식에서 파라미터 str의 타입을 명시적으로 지정하지 않는다. //이 경우에는 컴파일러가 컨텍스트와 함수형 인터페이스에 기반하여 형식을 추론. //Function<String, String>에 따라 String 타입의 파라미터를 받고 String 타입을 반환하는 함수를 나타냄.
지역 변수 사용
람다 캡처링 : 람다 표현식에서 익명 함수가 하는 것처럼 자유변수(파라미터로 넘겨진 변수가 아닌 외부에서 정의된 변수)를 활용하는 것.
하지만 이렇게 사용을 하려면 지역변수는 명시적으로 final로 선언되어 있거나 실질적으로 final로 선언된 변수와 똑같이 사용되어야 됨.
reacted with thumbs up emoji reacted with thumbs down emoji reacted with laugh emoji reacted with hooray emoji reacted with confused emoji reacted with heart emoji reacted with rocket emoji reacted with eyes emoji
Uh oh!
There was an error while loading. Please reload this page.
-
[CHAPTER 3] - 람다 표현식
람다
람다 표현식은 익명함수를 단순화한 것
특징
람다 표현식은 파라미터, 화살표, 바디로 구성
람다 파라미터
(Apple a1, Apple a2)
화살표
화살표(->)는 람다의 파라미터와 바디를 구분한다.
람다 바디
두 사과의 무게를 비교한다.
람다의 반환값에 해당하는 표현식.
a1.getWeight().compareTo(a2.getWeight());
람다 예시코드
람다 기본 문법
(parameters) -> expression
(parameters) -> {statements;}
함수형 인터페이스
하나의 추상 메서드를 지정하는 인터페이스.
많은 디폴트 메서드가 있어도 추상 메서드가 오직 하나면 함수형 인터페이스이다.
@FunctionalInterface
라는 어노테이션으로 함수형 인터페이스임을 나타내준다.이러한 함수형 인터페이스를 직접 구현한 인스턴스가
람다 표현식이다.
함수 디스크립터
함수 디스크립터
: 람다 표현식의 시그니처를 서술하는 메서드Runnable
인터페이스의 유일한 메서드abstractMethod
는 파라미터와 반환값이 없으므로Runnable 인터페이스는 인수와 반환값이 없는 시그니처라고 생각할 수 있다.
=> 파라미터를 받고 리턴을 명시하는 메서드가 함수 디스크립터다.
람다 활용
현재 코드는 파일에서 한 번에 한 줄만 읽을 수 있다.(
br.readLine()
)그렇다면 한 번에 두 줄을 읽게 하려면 어떻게 해야될까?
여기서 우리가 실제로 필요한 작업을 하는 곳은
br.readLine()
임으로 try-catch문은 껍데기로 볼 수 있다.그래서 훨씬 간결한 람다식을 사용해서 실제 필요한 작업을 파라미터로 전달하면
함수형 인터페이스 종류
제네릭 형식의 T객체를 인수로 받아 boolean을 반환하는 함수 디스크립터를 가짐
T 객체를 받아서 void를 반환하는 accept 추상메서드를 정의
T 객체를 인수로 받아서 제네릭 형식의 R 객체를 반환하는 추상 메서드 apply를 정의.
입력을 출력으로 매핑하는 람다를 정의할 때, Function 인터페이스를 활용할 수 있다.
박싱
: 자바에서 기본형을 참조형으로 변환하는 기능언박싱
: 참조형을 기본형으로 변환하는 기능오토박싱
: 박싱과 언박싱이 자동으로 이루어지는 기능형식 검사, 형식 추론, 제약
람다 표현식에는 람다가 어떤 함수형 인터페이스를 구현하는지에 관한 정보가 없다.
따라서 3가지의 방법으로 람다가 구현한 함수형 인터페이스를 확인할 수 있다.
형식검사
람다가 사용되는 context(메서드 파라미터, 변수 등)를 이용해서 람다의 type을 추론할 수 있다.
(Apple apple) -> apple.getWeight() > 150
는 Predicate를 의미한다. -> 이것이 target type위 예제에서 람다 표현식은 Apple을 인수로 받아 boolean을 리턴하기 때문에 유효한 코드다.
같은 람다, 다른 함수형 인터페이스
동일한 람다 표현식이더라도 호환되는 추상 메서드를 가진 함수형 인터페이스가 여러 개 일수 있다.
Callable
,PrivilegedAction
인터페이스는 모두 인수를 받지 않으며 제네릭 형식 T를 반환하는 디스크럽터를 가지고 있다.위와 같은 경우 context 추론에 의해
첫번째 줄의 target type은 Callable이고
두번째 줄의 target type은 PrivilegedAction
인 것을 추론할 수 있다.
예를 들어 Consumer context(
T -> void
)가 기대하는 void 대신 boolean을 반환해도 유효한 코드.Consumer b = s -> list.add(s);
만약 변환하는 타입도 같고, Target type, 함수 디스크립터 마저도 동일하다면 어떤 함수형 인터페이스를 가리키는지 명확하지 않게 된다.
그럴 땐, 캐스트를 해서 명확하게 함수형 인터페이스를 지정해주면 된다.
형식 추론
자바 컴파일러는 람다 표현식이 사용된 context를 이용해서 람다 표현식과 관련된 함수형 인터페이스를 추론한다.
함수 디스크립터를 알 수 있기 때문에 람다의 시그니처도 추론이 가능하다.
그래서 자바 컴파일러는 람다 표현식의 파라미터 형식을 추론할 수 있으므로 파라미터의 Type을 명시적으로 지정하지 않아도 된다.
지역 변수 사용
람다 캡처링
: 람다 표현식에서 익명 함수가 하는 것처럼 자유변수(파라미터로 넘겨진 변수가 아닌 외부에서 정의된 변수)를 활용하는 것.하지만 이렇게 사용을 하려면 지역변수는 명시적으로 final로 선언되어 있거나 실질적으로 final로 선언된 변수와 똑같이 사용되어야 됨.
Beta Was this translation helpful? Give feedback.
All reactions