Java8 새 특성 Lambda 표현식 인스턴스 상세 정보
6550 단어 Java8새로운 기능Lambda 표현식
Lambda 표현식을 설명하기 전에 먼저 하나의 방법만 있는 Interface (일반적으로 리셋 인터페이스라고 함) 를 살펴보겠습니다.
public interface OnClickListener {
void onClick(View v);
}
우리는 그것을 이렇게 사용한다.
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
v.setText("lalala");
}
});
이런 리셋 모델은 각종 프레임워크에서 매우 유행하지만 위와 같은 익명 내부 클래스는 좋은 선택이 아니다. 왜냐하면
button.setOnClickListener(v -> v.setText("lalala"));
어때?!다섯 줄 코드는 한 줄로 하면 돼!!!여기에 개념 함수식 인터페이스를 보충한다.앞에서 언급한 OnClickListener 인터페이스는 단지 하나의 방법일 뿐이다. 자바에서 대부분의 리셋 인터페이스는 이런 특징을 가지고 있다. 예를 들어 Runnable와Comparator;우리는 이 방법 하나만 가지고 있는 인터페이스를 함수식 인터페이스라고 부른다.
1. Lambda 표현식
익명 내부 클래스의 가장 큰 문제는 군더더기 문법이다. 예를 들어 앞의 On Click Listener에서 다섯 줄 코드가 한 줄만 작업을 수행하고 있다는 것이다.Lambda 표현식은 익명 방법이다. 앞에서 우리는 그것이 매우 가벼운 문법으로 이 문제를 해결한 것을 보았다.
다음은 Lambda 표현식의 몇 가지 예를 보여 줍니다.
(int x, int y) -> x + y // x y
() -> 66 // 66
(String name) -> {System.out.println(name);} //
(View view) -> {view.setText("lalala");} // View setText
Lambda 표현식 구문은 매개변수 목록, -> 및 함수체로 구성됩니다.함수체는 표현식일 수도 있고 코드 블록일 수도 있다.표현식: 표현식이 실행되고 결과를 되돌려줍니다.그것은 리턴 키워드를 간소화했다.
코드 블록: 말 그대로 코드 덩어리입니다. 일반적인 방법의 문장과 같습니다.
2. 목표 유형
앞의 예를 통해 알 수 있듯이 lambda 표현식은 이름이 없습니다. 그러면 우리는 그 유형을 어떻게 알 수 있습니까?답은 상하문을 통해 유도된 것이다.예를 들어, 다음 표현식의 유형은 OnClickListener입니다.
OnClickListener listener = (View v) -> {v.setText("lalala");};
이것은 같은lambda표현식이 서로 다른 상하문에서 서로 다른 유형을 가지고 있음을 의미한다
Runnable runnable = () -> doSomething(); // Runnable
Callback callback = () -> doSomething(); // Callback
컴파일러는 lambda 표현식이 있는 상하문에서 기대하는 유형을 이용하여 표현식의 유형을 유도하는데 이 기대되는 유형은 목표 유형이라고 부른다.lambda 표현식은 목표 형식이 함수식 인터페이스인 상하문에만 나타날 수 있습니다.Lambda 표현식의 유형과 목표 유형의 방법은 서명이 일치해야 합니다. 컴파일러는 이를 검사합니다. 하나의 lambda 표현식이 목표 유형 T에 값을 부여하려면 아래의 모든 조건을 만족시켜야 합니다.
// s1 s2 String
Comparator<String> c = (s1, s2) -> s1.compareTo(s2);
//
button.setOnClickListener(v -> v.setText("lalala"));
ps: Java7의 범용 방법과 <> 구조기도 목표 유형을 통해 유형을 유도합니다. 예를 들어 다음과 같습니다.
List<Integer> intList = Collections.emptyList>();
List<String> strList = new ArrayList<>();
3. 역할 영역내부 클래스에서 변수 이름과this를 사용하면 오류가 발생하기 쉽습니다.내부 클래스는 계승된 구성원 변수 (object 포함) 를 통해 외부 클래스의 구성원 변수를 덮어쓸 수 있으며, 제한되지 않은this 인용은 외부 클래스가 아닌 내부 클래스 자신을 가리킨다.
한편, 람다 표현식의 의미는 매우 간단하다. 이것은 부류에서 어떠한 변수도 계승하지 않고 새로운 작용역을 도입하지 않는다.lambda 표현식의 매개 변수와 함수체 안의 변수는 외부 환경의 변수와 같은 의미를 가진다.
다음은 우리 밤을 들자!
public class HelloLambda {
Runnable r1 = () -> System.out.println(this);
Runnable r2 = () -> System.out.println(toString());
@Override
public String toString() {
return "Hello, lambda!";
}
public static void main(String[] args) {
new HelloLambda().r1.run();
new HelloLambda().r2.run();
}
}
위의 코드는 결국 두 개의 Hello, lambda!를 출력합니다.이와 유사한 내부 클래스는 HelloLambda$와 유사하게 인쇄됩니다.1@32a890및 HelloLambda$1@6b32098이런 의외의 문자열.총괄: 어법 작용역의 이념을 바탕으로 lambda 표현식은 그 상하문의 국부 변수를 덮을 수 없다.
4. 변수 캡처
Java7에서 컴파일러는 내부 클래스에서 인용하는 외부 변수 (즉 포획된 변수) 에 대한 요구가 매우 엄격합니다. 포획된 변수가final로 선언되지 않으면final로 컴파일 오류가 발생합니다.그러나 Java8에서 이 제한을 완화한 C는 lambda 표현식과 내부 클래스에 대해 유효한 읽기 전용에 부합되는 국부 변수를 포획할 수 있습니다. 만약에 국부 변수가 초기화된 후에 수정된 적이 없다면 유효한 읽기 전용입니다.
Runnable getRunnable(String name){
String hello = "hello";
return () -> System.out.println(hello+","+name);
}
this의 인용과this를 통해 한정되지 않은 필드에 대한 인용과 한정되지 않은 방법의 호출은 본질적으로final 국부 변수를 사용하는 데 속한다.이런 인용을 포함하는lambda 표현식은this 실례를 포획한 것과 같다.다른 경우,lambda 대상은this에 대한 응용을 보류하지 않습니다.이 특성은 메모리 관리에 매우 좋다. 자바에서 비정적 내부 클래스가 외부 클래스의 실례를 기본적으로 가지고 있다는 것을 알아야 한다. 이것은 메모리 유출을 초래할 수 있다.lambda 표현식에서 외부 클래스 구성원을 포획하지 않으면 외부 클래스 실례에 대한 인용을 보류하지 않습니다.
그러나 자바8은 포획 변수에 대한 문법적 제한을 완화했지만 포획 변수를 수정하려는 행위는 금지되었다. 예를 들어 다음과 같은 예는 불법이다.
int sum = 0;
list.forEach(i -> {sum += i;});
왜 이런 행위를 금지해야 합니까?왜냐하면 이런 람다 표현식은 레이스 상태를 일으키기 쉬워요.lambda 표현식이 포획 변수를 수정하는 것을 지원하지 않는 또 다른 이유는 우리가 같은 효과를 실현하기 위해 더 좋은 방법을 사용할 수 있기 때문이다. 규정 (condition) 을 사용하는 것이다.java.util.stream 패키지는 Java8의 Stream API에 대해 다음 장에 설명합니다.
5. 방법 인용
lambda 표현식은 익명 방법을 정의하고 함수식 인터페이스로 사용할 수 있도록 합니다.Java8은 기존 방법에서 동일한 특성을 구현할 수 있습니다.
방법 인용과lambda표현식은 같은 특성을 가지고 있다. (그들은 모두 목표 유형이 필요하고 함수식 인터페이스로 전환되는 실례가 필요하다.) 그러나 우리는 방법 인용에 방법체를 제공할 필요가 없다. 우리는 방법명을 통해 기존의 방법을 직접 인용할 수 있다.
다음 코드를 예로 들면, userName에 따라 정렬해야 한다고 가정합니다
class User{
private String userName;
public String getUserName() {
return userName;
}
...
}
List<User> users = new ArrayList<>();
Comparator<User> comparator = Comparator.comparing(u -> u.getUserName());
Collections.sort(users, comparator);
우리는 방법으로 위의 lambda 표현식을 인용하여 바꿀 수 있다
Comparator<User> comparator = Comparator.comparing(User::getUserName);
여기 User::get UserName은 lambda 표현식의 약자로 간주됩니다.비록 방법 인용이 반드시 코드를 더욱 치밀하게 만드는 것은 아니지만, 그것은 더욱 명확한 의미를 가지고 있다. 만약 우리가 호출하고자 하는 방법이 하나의 이름을 가지고 있다면, 우리는 방법명을 통해 그것을 호출할 수 있다.메소드 참조에는 다음과 같은 여러 가지 구문이 있습니다.
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
Java 8 새 기능 내장 함수식 인터페이스 상세 정보Java 8 새로운 기능 내장 함수식 인터페이스 이전의 블로그 람다 표현식에서 자바 8이 제공하는 함수식 인터페이스를 언급한 적이 있다.이 글에서 자바 8의 가장 기본적인 함수식 인터페이스를 소개할 것이다 방법의 인...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.