※@FunctionalInterface
java8在介面上可加這個annotation,表示裡面一定只能剛好有一個未實作的method,不能少也不能多(連繼承的也算),但覆寫 Object 的 public 方法不會納入計算,驗證沒過都會報「InterfaceName is not a functional interface」的錯,但default、static沒有關係不加上這個參數也是可以,和@Override一樣,有加的話,錯誤可以在編譯期就發現
※無參數無回傳值
@FunctionalInterface interface I1 { void fi(); } public class Java8Test { public static void main(String[] args) { I1 test = new I1() { @Override public void fi() { System.out.println("使用匿名1"); } }; test.fi(); new I1() { @Override public void fi() { System.out.println("使用匿名2"); } }.fi(); I1 lambda1 = () -> { System.out.println("使用Lambda-1"); }; lambda1.fi(); /* * 不可合併成: * () -> { System.out.println("使用Lambda-1"); }.fi(); * 因為 {} 還不知道要 assign 給哪一個介面,但可以強轉,下一個例子有 */ I1 lambda2 = () -> System.out.println("使用Lambda-2"); lambda2.fi(); } }
※匿名類別在編譯成.class時,會多一個「ClassName$1.class」檔案,但lambda不會產生
※():參數,如果介面上定義的是int,那就要寫(int i),不能寫Integer,編譯不會過,但類型可以省略不寫
->:固定的語法
{}:實作的內容
※() -> {}把它想成在寫匿名類別,然後用介面唯一的方法呼叫
※強轉
@FunctionalInterface interface I1 { void fi(); } public class Java8Test { public static void main(String[] args) { ((I1) () -> { System.out.println("xxx"); }).fi(); } }
※其他的參數和回傳值
@FunctionalInterface interface I1 { void fi(int i); } @FunctionalInterface interface I2 { void fi(int i, int j); } @FunctionalInterface interface I3 { String fi(); } @FunctionalInterface interface I4 { int fi(int i, int j); } public class Java8Test { public static void main(String[] args) { I1 lambda1a = (x) -> { System.out.println("I1a=" + x); }; lambda1a.fi(1); I1 lambda1b = x -> System.out.println("I1b=" + x); lambda1b.fi(1); I2 lambda2a = (x, o) -> { System.out.println("I2a=" + x + ", " + o); }; lambda2a.fi(1, 2); I2 lambda2b = (x, o) -> System.out.println("I2b=" + x + ", " + o); lambda2b.fi(1, 2); I3 lambda3a = () -> { return "call success"; }; System.out.println("I3a=" + lambda3a.fi()); // 沒有「{}」時,連「return」關鍵字也不能有 I3 lambda3b = () -> "call success"; System.out.println("I3b=" + lambda3b.fi()); I4 lambda4a = (x, o) -> { return x + o; }; System.out.println("I4a=" + lambda4a.fi(1, 2)); I4 lambda4b = (x, o) -> x + o; System.out.println("I4b=" + lambda4b.fi(1, 2)); } }
※結果:
I1a=1
I1b=1
I2a=1, 2
I2b=1, 2
I3a=call success
I3b=call success
I4a=3
I4b=3
※參數的型態可省略
※有b的都是簡便寫法,參數只有一個時,可以省略圓括號
※如果只有一行時,可以省略「{}」,而且如果有回傳值,連 return 關鍵字也不能有
※圖括號裡的參數是隨便打的,呼叫時,如lambda1a.fi(1),此時會將1傳給x
※介面為參數
@FunctionalInterface interface I1 { void fi(); } public class Java8Test { public void xxx(I1 i1) { System.out.println(i1); i1.fi(); } public static void main(String[] args) { new Java8Test().xxx(new I1() { @Override public void fi() { System.out.println("使用匿名" + System.getProperty("line.separator")); } }); new Java8Test().xxx(() -> System.out.println("使用Lambda")); } }
※結果:
Java8Test$1@2a139a55
使用匿名
Java8Test$$Lambda$1/834600351@548c4f57
使用Lambda
和匿名比較起來,會在類名後加上「$$Lambda」,當然匿名還是會產生class,而lambda還是不會產生class
※使用外部變數
※int i = 0; I1 ia = new I1() { int j = 0; @Override public void m() { System.out.println(i); System.out.println(++j); } }; ia.m(); int k = 0; I1 ib = () -> { int l = 0; System.out.println(k); System.out.println(++l); }; ib.m();
※上面是匿名,下面是lambda
1.7(含) 之前,i 變數必需是 final,否則編譯錯誤
但 1.8 可不用寫 final 了,但如果你想改變 i 的值,假設 ++i,還是會編譯錯誤,也就是還是 final
相同的道理,lambda 也會有一樣的問題,指的是 i 和 k 變數,不是 j 和 l 變數
沒有留言:
張貼留言