※@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 變數
沒有留言:
張貼留言