學習筆記
作爲學習筆記我就不寫歷史啥的了,完全隨心記。
首先,Java lamda的標準寫法
(param1, param2) -> {expression};
param爲匿名內部類中的函數參數,expression爲函數裏面的所有語句,常寫的例子
new Thread(new Runnable() {
@Override
public void run() {
// doSomething
System.out.println("test");
}
}).start();
這裏匿名內部類可省略,編譯器會自動推斷,函數沒有參數就可直接使用括號,函數內部語句直接寫到花括號中,lambda表達式如下
new Thread(() -> {
System.out.print("test");
}).start();
接下來又是很重要的一點
如果參數只有一個,小括號可以去掉 即爲
param -> {expression};
比如
jButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
System.out.println("Action performed");
e.getActionCommand();
}
});
這裏只有ActionEvent類的一個對象e爲參數,裏面有兩行代碼,所以可以省略掉參數外面的括號,而且參數可以自己定義爲任何合法的標識符,但是在函數內部引用的時候需要與你定義的參數保持一致,這裏就變成了
jButton.addActionListener(w-> {
System.out.println("Action performed");
w.getActionCommand();
});
好的,語法還可以進一步簡化
如果表達式只有一行,大括號,可以去掉,並且這一行最後的分號結尾,要去掉
最開始寫的新建線程的lambda表達式可以進一步簡化成這樣
new Thread(() -> System.out.println("test")).start();
那麼,這是java8的新特性,什麼情況下能使用lambda表達式呢?我們看到的形式都是在創建匿名內部類的時候使用lambda表達式,創建形式就是new一個某個接口類型的對象,然後在內部類中實現接口的方法。那麼,這些接口都有什麼特點呢,通過Idea打開Runnable接口的定義,會發現接口上面有這麼一個註解
@FunctionalInterface
即函數式接口,那我們再看看這個接口的定義吧
An informative annotation type used to indicate that an interface type declaration is intended to be a functional interface as defined by the Java Language Specification.
Conceptually, a functional interface has exactly one abstract method. Since {@linkplain java.lang.reflect.Method#isDefault() default methods} have an implementation, they are not abstract. If an interface declares an abstract method overriding one of the public methods of {@code java.lang.Object}, that also does not count toward the interface’s abstract method count since any implementation of the interface will have an implementation from {@code java.lang.Object} or elsewhereNote that instances of functional interfaces can be created with lambda expressions, method references, or constructor references.
If a type is annotated with this annotation type, compilers are required to generate an error message unless:
- The type is an interface type and not an annotation type, >enum, or class.
- The annotated type satisfies the requirements of a functional interface.
However, the compiler will treat any interface meeting the definition of a functional interface as a functional interface regardless of whether or not a {@code FunctionalInterface} annotation is present on the interface declaration.
從這段解釋裏面我們可以提取到幾個要點
- 首先這個註解是定義在接口上面的
- 第二,接口由這個註解定義的接口應該有且僅有一個抽象方法,但是由於Java8引入了接口的default方法,default方法有實現,所以不算抽象方法,如果接口覆寫了object的一個public方法,也不計算在這個抽象方法的名額裏面,因爲所有的接口的實現都會實現object的方法。
- 第三,函數式接口的實例可以lambda expressions, method references, or constructor references的形式出現
- 第四,不在以上範圍內的接口如果使用了FunctionalInterface註解,編譯器會報錯
- 最後,雖然有些接口沒有加上FunctionalInterface註解,但是編譯器會把滿足函數式接口的定義的接口看作FunctionalInterface,也就是說這些接口的實例也可以用lambda表達式的形式來寫。
也就是說,所有滿足函數式接口的接口的實例都可以變爲lambda表達式,不滿足的則會在創建的時候報錯。
以下定義的接口就滿足函數式接口的定義
public interface MyTest {
String[] test(String str);
default void test2() {
System.out.println("test");
}
String toString();
}
雖然沒有加上FunctionalInterface註解,但是在使用的時候還是可以使用Lambda表達式
public class MyTestMain {
public static void main(String[] args) {
// MyTest.test(str)常規寫法;
String[] test = test(new MyTest() {
@Override
public String[] test(String str) {
return str.split("");
}
});
//變爲lambda表達式
test(s->s.split(""));
for (String s : test) {
System.out.println(s);
}
}
public static String[] test(MyTest test) {
return test.test("strd");
}
}
到這裏就可以使用lambda表達式寫很多有意思的代碼啦,仔細觀察,java集合裏面好多的匿名內部類都可以使用lambda表達式來簡寫,我們看了函數式接口用lambda表達式來表示的,當然要介紹一下使用方法引用的形式咯
如果,lambda 表達式只有一個參數,表達式只有一個, 且表達式調用了這個的參數本身,那麼這個參數可以省略,並且變成方法引用的形式
對象::方法名
對象爲表達式中的對象,方法爲該對象調用的方法
appleStore.forEach(apple -> System.out.println(apple));
apple爲參數,表達式裏面調用了apple,且表達式只要一個,可以轉化爲方法引用的形式
appleStore.forEach(System.out::println);
方法引用還有一種形式
當表達式爲前述參數只調用一次自己的方法,也可以變爲方法引用
參數類名::方法名
int redPriceSum = appleStore.stream()
.filter(apple -> apple.getColor().equals("red"))
.mapToInt(apple1->apple1.getPrice).sum();
可以看到mapToInt方法中的lambda表達式符合上述方法引用的形式,所以可以簡化爲
Apple::getPrice
其中Apple爲apple對象的類名
大致就是這些,想要了解更多使用的實例的可以去翻一翻集合的源碼,比如集合類的foreach方法,參數就是一個函數式接口,可以轉換爲lambda表達式,真的太寶藏啦!我現在才發現在Idea上面看源碼是多麼有意思,以後要常看常學!