람다 표현식을 사용하는 이유
몇 가지 예를 살펴 보겠습니다.
첫 번째 예는 별도의 스레드에서 작업을 실행하는 것인데, 일반적으로 우리는 일반적으로 다음과 같이 구현하는 것입니다.
클래스 작업자는 runnable {public void run () {for (int i = 0; i <100; i ++) dowork (); } ...} Worker W = New Worker (); 새 스레드 (w) .start ();두 번째 예제는 일반적으로 수행되는 사용자 정의 문자열 비교 방법 (문자열 길이)입니다.
클래스 longth comparator implements emplements emportements <string> {public int compar (string first, string second) {return integer.compare (first.length (), second.length ()); }} arrays.SORT (문자열, 새로운 longthcomparator ());셋째 예제에서 Javafx에서는 버튼에 콜백을 추가합니다.
button.setonaction (new EventHandler <CationEvent> () {public void handle (actionEvent event) {system.out.println ( "클릭 해 주셔서 감사합니다!");}});이 예제는 공통점이 있는데, 이는 먼저 코드 블록을 정의하고 객체 또는 방법으로 전달한 다음 실행한다는 것입니다. Lambda 표현식 전에 Java는 객체 지향적이기 때문에 Java는 코드 블록의 직접 통과를 허용하지 않으므로 객체를 전달하여 객체에 실행될 코드 블록을 캡슐화해야합니다.
람다 발현 구문
위의 두 번째 예에서 길이 비교기는 Lambda 표현으로 표현됩니다.
(String First, String Sec
-> 이전은 매개 변수 목록이며, 표현식 명령문 본문이 뒤 따릅니다.
표현식 진술의 본문이 둘 이상의 줄인 경우, 진술의 본문은 일반적인 기능과 마찬가지로 {}에 기록됩니다.
(string first, string sec } else if (first.length () == sucle.length ()) {return 0; } else {return -1; }};매개 변수가없는 경우 ()는 여전히 귀하와 함께 가져와야합니다. 예를 들어, 위의 첫 번째 예는 다음과 같이 표현 될 수 있습니다.
() -> {for (int i = 0; i <1000; i ++) {dowork (); }}컨텍스트에서 매개 변수 유형을 자동으로 추론 할 수있는 경우 다음을 생략 할 수 있습니다.
비교기 <string> comp = (첫 번째, 두 번째) // (string first, string second) -> integer.compare (first.length (), second.length ());
매개 변수가 하나만 있고 유형을 자동으로 추론 할 수 있다면 브래킷 ()도 생략 할 수 있습니다.
// 대신 (이벤트) -> 또는 (ActionEvent event) -> eventHandler <ActionEvent> Listener = event-> system.out.println ( "클릭 해 주셔서 감사합니다!");
Lambda 발현의 반환 값의 유형은 자동으로 추론되므로 지정할 필요가 없습니다. Lambda 표현식에서 일부 조건부 분기에는 반환 값이 있지만 다른 지점에는 반환 값이 없으며 다음과 같은 등장 할 수 없습니다.
(x) -> {if (x> = 0) {return 1; }}또한, Expression Lambda와 문장 Lambda의 차이점은 Expression Lambda가 리턴 키워드를 작성할 필요가 없다는 것입니다. Java Runtime은 표현식의 결과를 리턴 값으로 반환하고 Statement Lambda는 {}에 작성된 표현식이며, 예를 들어 반품 키워드를 사용해야합니다.
// expression lambdacomparator <string> comp1 = (첫 번째, 두 번째) -> integer.compare (first.length (), second.length ()); // state lambdacomparator <string> comp2 = (첫 번째, 두 번째) -> {return integer.compare (first.length (), 두 번째 .length (}); 기능 인터페이스
인터페이스에 하나의 추상 방법 만 있으면
런 가능, 비교기 등과 같은 기능 인터페이스
기능적 인터페이스 객체가 필요한 곳에서는 Lambda 표현식을 사용할 수 있습니다.
arrays.sort (단어, (첫 번째, 두 번째) -> integer.compare (first.length (), second.length ());
여기서 SORT ()의 두 번째 매개 변수는 비교기 객체가 필요하고 비교기는
기능적 인터페이스이므로 Lambda 표현식으로 직접 전달할 수 있습니다. 객체의 비교 () 메소드를 호출 할 때 Lambda 표현식에서 진술 본문을 실행하는 것입니다.
Lambda Expression의 진술이 예외를 던지면 기능 인터페이스의 해당 추상 방법은 예외를 던져야합니다. 그렇지 않으면 Lambda 표현식에서 예외를 명시 적으로 포착해야합니다.
runnable r = ()-> {system.out.println ( "-------"); try {thread.sleep (10); } catch (InterruptedException e) {// catch exception}}; callable <string> c = ()-> {system.out.println ( "----------"); Thread.sleep (10); 반품 "";}; 메소드 참조
Lambda 표현식의 매개 변수가 방법으로 매개 변수로 전달되고 실행 효과가 동일하면 Lambda 표현식은 메소드 참조를 사용하여 표현 될 수 있고 다음 두 가지 방법은 다음과 같습니다.
(x) -> system.out.println (x) system.out :: println
그중에서도 System.out :: println을 메소드 참조라고합니다.
메소드 참조는 주로 세 가지 형태로 제공됩니다.
처음 두 가지 방법의 경우, 해당 LAMBDA 표현 파라미터 및 메소드 파라미터는 다음과 같이 동일합니다.
System.out :: println (x) -> system.out.println (x) math :: pow (x, y) -> math.pow (x, y)
세 번째 방법의 경우, 해당 LAMBDA 표현 명령문 본체에서 첫 번째 매개 변수는 객체로 사용되며 방법이 호출되고 다른 매개 변수는 다음과 같은 메소드 매개 변수로 사용됩니다.
String :: ComparetOignoreCase (S1, S2) -> S1.comparetoignorecase (S2) 1.5 생성자 참조
생성자 참조는 메소드 참조와 유사하지만 특별한 방법입니다. 특정 생성자는 다음과 같은 컨텍스트 환경에 의해 결정됩니다.
list <string> labels = ...; stream <button> stream = labels.stream (). map (button :: new);
버튼 :: new는 (x) -> 버튼 (x)에 해당하므로 다음은 다음과 같습니다. 버튼 (x);
단일 객체를 만드는 것 외에도 다음 두 가지 등가와 같은 다양한 객체를 만들 수도 있습니다.
int [] :: new (x) -> new int [x]
가변 범위
LAMBD 표현식은 다음과 같은 현재 범위에서 사용 가능한 변수를 캡처합니다.
public void repetmessage (문자열 텍스트, int count) {runnable r = () -> {for (int i = 0; i <count; i ++) {system.out.println (텍스트); thread.yield (); }}; 새 스레드 (r) .start ();}그러나 이러한 변수는 불변이어야합니다. 다음 예를 참조하십시오.
int matches = 0; for (path p : files) 새 스레드 (() -> {if (p가있는) 일치 ++;}). start (); // 매치를 돌연변이하는 데 불법입니다람다 표현식에서는 돌연변이 변수가 스레드-안전하지 않기 때문에, 이는 내부 클래스의 요구 사항과 일치하며 외부 정의 된 최종 변수 만 내부 클래스에서 참조 할 수 있습니다.
Lambda 표현식의 범위는 중첩 코드 블록의 범위와 동일하므로 LAMBD 표현식의 매개 변수 이름 또는 변수 이름은 다음과 같은 로컬 변수와 충돌 할 수 없습니다.
Path First = paths.get ( "/usr/bin"); 비교기 <string> comp = (첫 번째, 두 번째) -> integer.compare (first.length (), second.length ()); // 오류 : 가변은 이미 이미 정의되었습니다
이 변수가 Lambda 표현식으로 참조되는 경우, 참조는 다음과 같은 Lambda 표현식을 생성하는 방법의 변수입니다.
public class application () {public void dowork () {runnable runner = () -> {...; System.out.println (this.toString ()); ...}; }} 그래서 여기에 this.toString ()는 응용 프로그램 객체의 toString ()을 호출합니다.
사물.
기본 방법
인터페이스에는 추상적 인 방법 만있을 수 있습니다. 새 메소드가 기존 인터페이스에 추가되면 인터페이스의 모든 구현 클래스 가이 메소드를 구현해야합니다.
Java 8은 기본 메소드의 개념을 도입하고 기본 인터페이스 규칙을 파괴하지 않는 인터페이스에 기본 메소드를 추가합니다. 인터페이스 구현 클래스는 다음과 같은 기본 메소드를 재정의하거나 직접 상속하도록 선택할 수 있습니다.
인터페이스 사람 {long getId (); 기본 문자열 getName () {return "John Q. Public"; }}Java는 여러 상속을 허용합니다. 클래스의 상위 클래스에 정의 된 메소드가 인터페이스에 정의 된 기본 메소드와 정확히 동일하거나 클래스의 두 인터페이스가 정확히 동일하다면이 충돌을 처리하는 방법은이 충돌을 처리하는 방법이라면이 충돌을 처리하는 방법은이 충돌을 처리하는 방법은 무엇입니까? 처리 규칙은 다음과 같습니다.
메소드가 상위 클래스와 인터페이스 간의 충돌하는 경우 : 부모 클래스의 메소드가 우선하고 인터페이스의 메소드가 무시됩니다.
두 인터페이스의 기본 메소드가 충돌하는 경우 충돌을 해결하기 위해 방법을 무시해야합니다.
정적 방법
Java 8 이전에는 인터페이스에서 정적 변수 만 정의 할 수 있습니다. Java 8에서 시작하여 정적 메소드는 인터페이스에 추가 할 수 있습니다.
비교기 인터페이스는 다음과 같은 일련의 정적 방법을 추가했습니다.
public static <t> 비교기 <t> 비교 (tointfunction <? super t> keyextractor) {objects.requirenonnull (keyextractor); return (비교기 <t> & Serializable) (C1, C2) -> integer.compare (keyextractor.applyasint (c1), keyextractor.applyasint (c2));}이 정적 방법을 사용하면 다음 두 가지 방법도 다음과 같습니다.
1.
Arrays.sort (도시, (첫 번째, 두 번째) -> integer.compare (first.length (), second.length ()));
2.
Arrays.sort (도시, 비교기 .comparingint (String :: length));
따라서 향후 자체 인터페이스를 설계 할 때 더 이상 별도의 도구 클래스 (예 : 컬렉션/컬렉션)를 정의 할 필요가 없습니다.
인터페이스에서 정적 메소드를 사용하십시오.
익명의 내부 클래스
Java World에서 익명의 내부 클래스는 응용 프로그램에서 한 번만 수행 할 수있는 작업을 구현할 수 있습니다. 예를 들어, Android 애플리케이션에서는 버튼 클릭 이벤트가 처리됩니다. 클릭 이벤트를 처리하기 위해 별도의 클래스를 작성할 필요가 없습니다. 익명의 내부 수업으로이를 수행 할 수 있습니다.
버튼 버튼 = (버튼) findViewById (r.id.button1); button.setOnclickListener (new onclickListener () {@override public void onclick (view view) {toast.maketext.this, "버튼 클릭", 토스트. length_short);}); Lambda 예제 1. 런닝 가능한 Lambda 몇 가지 예를 살펴 보겠습니다. 다음은 런 가능의 예입니다. public void RunnableTest () {System.out.println ( "=== runnableTest ==="); // 익명의 실행 가능한 runnable r1 = new Runnable () {@override public void run () {System.out.println ( "Hello World One!"); }}; // lambda runnable runnable r2 = () -> system.out.println ( "Hello World Two!"); // 두 실행 함수를 실행합니다. r1.run (); r2.run (); } public void RunnableTest () {System.out.println ( "=== runnableTest ==="); // 익명의 실행 가능한 runnable r1 = new Runnable () {@override public void run () {System.out.println ( "Hello World One!"); }}; // lambda runnable runnable r2 = () -> system.out.println ( "Hello World Two!"); // 두 실행 함수를 실행합니다. r1.run (); r2.run (); } 구현이나 반환 값이 반환되지 않습니다. 실행 가능한 람다 표현식은 코드 블록을 사용하여 5 가지 요소 코드를 하나의 문으로 단순화합니다. 공개 클래스 사람 {개인 문자열 givenname; 개인 문자열 성; 사적인 int 연령; 개인 성별 성별; 개인 문자열 이메일; 개인 문자열 전화; 개인 문자열 주소;} 공개 클래스 사람 {개인 문자열 givenname; 개인 문자열 성; 사적인 int 연령; 개인 성별 성별; 개인 문자열 이메일; 개인 문자열 전화; 개인 문자열 주소;} 다음은 익명의 내부 클래스 및 람다 표현식을 사용하여 비교기 인터페이스를 구현하는 방법입니다. public class comparatortest {public static void main (String [] args) {list <person> personlist = person.createShortList (); // 내부 클래스를 사용하여 정렬 Collections.SORT (PersonList, New Comparator <person> () {public int compare (person p1, person p2) {return p1.getSurname (). compareto (p2.getSurname ())); System.out.println ( "=== 분류 ASC 성 ==="); for (person p : personlist) {p.printname (); } // lambda expression을 사용한 구현 // 오름차순 system.out.println ( "=== 정렬 된 ASC 성 ==="); Collections.SORT (PersonList, (Person P1, Person P2) -> P1.GetSurname (). Compareto (p2.getSurname ())); for (person p : personlist) {p.printname (); } // desc secciational system.out.println ( "=== 정렬 된 desc 성 ==="); collections.sort (personList, (p1, p2) -> p2.getSurname (). compareto (p1.getSurname ()); for (person p : personlist) {p.printname (); }}} public class comparatortest {public static void main (String [] args) {list <person> personlist = person.createShortList (); // 내부 클래스를 사용하여 정렬 Collections.SORT (PersonList, New Comparator <person> () {public int compare (person p1, person p2) {return p1.getSurname (). compareto (p2.getSurname ())); System.out.println ( "=== 분류 ASC 성 ==="); for (person p : personlist) {p.printname (); } // lambda expression을 사용한 구현 // 오름차순 system.out.println ( "=== 정렬 된 ASC 성 ==="); Collections.SORT (PersonList, (Person P1, Person P2) -> P1.GetSurname (). Compareto (p2.getSurname ())); for (person p : personlist) {p.printname (); } // desc secciational system.out.println ( "=== 정렬 된 desc 성 ==="); collections.sort (personList, (p1, p2) -> p2.getSurname (). compareto (p1.getSurname ()); for (person p : personlist) {p.printname (); }}} 익명의 내부 클래스는 Lambda 표현을 통해 구현 될 수 있음을 알 수 있습니다. 첫 번째 람다 표현식은 매개 변수의 유형을 사람으로 정의합니다. 두 번째 람다 표현식은 유형 정의를 생략합니다. LAMBDA 표현식 지원 유형 녹다운을 지원하고 컨텍스트를 통해 필요한 유형을 추론 할 수 있다면 유형 정의를 생략 할 수 있습니다. 여기서는 일반적인 정의를 사용하는 비교기에서 Lambda 표현식을 사용하기 때문에 컴파일러는이 두 매개 변수를 사람으로 추론 할 수 있습니다.