先來看一個簡單的Lambda用法:java
//多行註釋中爲不使用Lambda的寫法 /** Runnable run = new Runnable() { @Override public void run() { System.out.println("Test") } }; */ Runnable run = () -> System.out.println("Test");
咱們來看一下Runnable接口:數組
@FunctionalInterface public interface Runnable { public abstract void run(); }
####咱們來看一下Java函數式接口【能夠用Lambda方式的接口】的定義: 在Java中,函數式接口是隻定義了一個抽象方法的接口。Java 8引入了FunctionalInterface註解來代表一個接口打算成爲一個函數式接口。在實際使用中無論FunctionalInterface註解是否存在,Java編譯器都會將全部知足該定義的接口看做是函數式接口。 下面咱們本身寫一個接口看一下可否如Runnable通常:app
/** * 拿客 * www.coderknock.com * QQ羣:213732117 * 建立時間:2016年07月22日 * 描述: */ public interface TestLambdaInterface { void testInterface(); }
咱們以下使用該接口,程序能正常編譯並輸出結果,說明Java編譯器都會將全部知足該定義的接口看做是函數式接口:ide
TestLambdaInterface test=()->System.out.println("Test"); test.testInterface();
#####接口中定義方法的返回值無關性證實: 當咱們將方法的返回值改爲String時:函數
TestLambdaInterface test=()->"test"; test.testInterface();
說明函數式接口與接口中定義方法的返回值無關 下面咱們在接口中增長一個方法:ui
/** * 拿客 * www.coderknock.com * QQ羣:213732117 * 建立時間:2016年07月22日 * 描述: */ public interface TestLambdaInterface { void testInterface(); void testInterface2(); }
編譯時:code
D:\Work\LearnJavaFX\src>javac -encoding utf-8 LambdaTest.java LambdaTest.java:20: 錯誤: 不兼容的類型: TestLambdaInterface 不是函數接口 TestLambdaInterface test = () -> System.out.println("Test"); ^ 在 接口 TestLambdaInterface 中找到多個非覆蓋抽象方法 1 個錯誤
#####default與static方法的無關性證實: 咱們再來看看Java中提供的BinaryOperator接口:對象
package java.util.function; import java.util.Objects; import java.util.Comparator; @FunctionalInterface public interface BinaryOperator<T> extends BiFunction<T,T,T> { public static <T> BinaryOperator<T> minBy(Comparator<? super T> comparator) { Objects.requireNonNull(comparator); return (a, b) -> comparator.compare(a, b) <= 0 ? a : b; } public static <T> BinaryOperator<T> maxBy(Comparator<? super T> comparator) { Objects.requireNonNull(comparator); return (a, b) -> comparator.compare(a, b) >= 0 ? a : b; } }
其實現的接口BiFunction:接口
package java.util.function; import java.util.Objects; @FunctionalInterface public interface BiFunction<T, U, R> { R apply(T t, U u); default <V> BiFunction<T, U, V> andThen(Function<? super R, ? extends V> after) { Objects.requireNonNull(after); return (T t, U u) -> after.apply(apply(t, u)); } }
該接口可使用以下方法生成實例:圖片
BinaryOperator<Long> add = (x, y) -> x + y;
說明函數式接口與接口中是否存在default與static方法無關 ####總結 充分說明能成爲函數式接口【可使用Lambda來簡化接口操做】的條件爲:只定義了一個抽象方法的接口。
import java.awt.event.ActionListener; import java.util.function.BinaryOperator; /** * 拿客 * www.coderknock.com * QQ羣:213732117 * 建立時間:2016年07月22日 * 描述: */ /** * 對於只有一個抽象方法且返回值爲void可使用下面的方法快捷的生成接口的實例 */ Runnable voidFunc = () -> System.out.println("沒有參數的函數式接口"); /** * 上面的聲明其實完整寫法應該爲: * Runnable voidFunc = () -> {System.out.println("沒有參數的函數式接口")}; * 對於只有一行語句時,能夠省略{}, * 下面是多行語句的狀況,{}不能省略 */ Runnable muitiStatement = () -> { System.out.println("第一行"); System.out.println("第二行"); //多行語句.... }; /** * 對於有接口中有參數哦的方法咱們可使用 * ActionListener oneParam = (event) -> System.out.println("一個參數"); * 當只有一個參數時,能夠省略()以下: */ ActionListener oneParam = event -> System.out.println("一個參數"); /** * 多參數就必須將參數放入到()中調用,按照參數順序寫入 */ BinaryOperator<Long> add = (x, y) -> x + y; /** * 上面幾種狀況中,接口的參數在編譯時進行類型的推斷,咱們亦能夠顯式聲明一下【這樣能夠避免不少錯誤】 */ BinaryOperator<Long> add2 = (Long x, Long y) -> x + y;
在JDK8對匿名內部類中調用類以外變量必須爲final的限制進行了必定的放寬:
String name = "123"; Runnable run = new Runnable() { @Override public void run() { //在JDK8以前下面的語句是會報錯的,只有name是final時纔可使用,可是JDK8中,這樣的語句就不會報錯 System.out.println(name); } };
雖然JDK8中上面的語句時能夠的,但這只是減小了咱們代碼中的編寫,編譯時仍是會將name當作是final因此當有如下幾種狀況時,編譯仍是會報錯:
//1.對name進行了第二次賦值,這樣編譯器就會認爲name不是final類型 String name = "123"; name=""; Runnable run = () -> { System.out.println(name); }; //2.在匿名類方法中對變量進行賦值也是不容許的 String name = "123"; Runnable run = () -> { name=""; System.out.println(name); };
若是真的須要在Lambda中或者匿名中對變量賦值,那麼應該將其放入數組,或者當作一個類的屬性來傳遞【對象final時能夠設置其屬性,不能設置其引用】。 ####IDEA中快速生成Lambda語句