瞭解Lambda表達式之前,需要對匿名內部類與函數式接口瞭解。
一、函數式接口
1.有且只有一個抽象方法,但可以有多個非抽象方法。
2.可以隱式的轉換爲 Lambda 表達式。
3.可以在任意函數式接口上使用 @FunctionalInterface 註解,這樣做可以檢查它是否是一個函數式接口,同時javadoc也會包含一條聲明,聲明這個接口是一個函數式接口。
在 JDK1.8之前,java就包含了許多函數式接口,
java.lang.Runnable ,java.util.concurrent.Callable ,java.security.PrivilegedAction ,java.awt.event.ActionListener ,
java.io.FileFilter ,java.nio.file.PathMatcher ,java.lang.reflect.InvocationHandler ,java.beans.PropertyChangeListener ,
java.util.Comparator ,javax.swing.event.ChangeListener
java8 新增 java.util.function ,包下包含多個函數式接口,用來支持函數式編程。
/**
* @author YoonaLt
* 有參數,無返回值 的函數式接口
*/
@FunctionalInterface
public interface MyFunctionalInterface {
/**
* 函數式接口有且僅有一個抽象方法
* 接口中,成員變量的默認修飾符爲 public static final,成員方法的默認修飾符爲 public abstract.
*
* @param s 參數
*/
void onlyAbstractMethod(String s);
/**
* 可以含有多個其他非抽象方法
* 這個方法是一個默認方法,使用默認方法的優勢是給接口添加新方法的同時不影響已有的實現.在工作中解
* 決接口的修改與現有的實現不兼容的問題是非常有效的.
*/
default void otherFunction() {
System.out.println("這是函數式接口的非抽象方法,可以有多個");
}
}
二、Lambda表達式
Lambda 表達式,也可稱爲閉包,它是推動 Java 8 發佈的最重要新特性。Lambda 允許把 函數 作爲一個方法的 參數(函數作爲參數傳遞進方法中)。
使用Lam不打可以代替匿名內部類,匿名方法的使用,簡化代碼,減少類文件的生成。但是代碼可讀性不高,使用場景有限制。
Lambda表達式的寫法一般爲
(parameters) -> expression 或 (parameters) ->{ statements; }
其重要特性爲
- 可選類型聲明:不需要聲明參數類型,編譯器可以統一識別參數值。
- 可選的參數圓括號:一個參數無需定義圓括號,但多個參數需要定義圓括號。
- 可選的大括號:如果主體只包含了一個語句,就不需要使用大括號。
- 可選的返回關鍵字:如果主體只有一個表達式返回值則編譯器會自動返回值,大括號需要指定明表達式返回了一個數值。
//無參,使用空的 () 表示
() -> body
// 一個參數,參數可以用 () 包裹,也可以不用.當 body 主體只包含一個語句時,花括號可以省略不寫, param -> body;
(param) -> { body; } 或 param -> { body; }
// 多個參數
(param1, param2...) -> { body }
參數 param param1 param2 的類型不需要指定(typeOne param1,typeTwo param2),編譯器可以從上下文推斷參數類型.
1.上面示例 有參數,無返回值 的函數式接口轉變爲 Lambda 表達式爲
MyFunctionalInterface myFunctionalInterface = (s) -> System.out.println(s);
方法引用的方式
MyFunctionalInterface myFunctionalInterface = System.out::println;
myFunctionalInterface.onlyAbstractMethod("轉換爲Lambda表達式");
2.有參數,有返回值的函數式接口
/**
* @author YoonaLt
* 有參數,有返回值的函數式接口
*/
@FunctionalInterface
public interface MyTest<T, E> {
E myMethod(T t);
}
轉變爲Lambda表達式爲
MyTest<String, Integer> myTest = (s) -> {return Integer.parseInt(s);};
方法引用的方式
MyTest<String, Integer> myTest = = Integer::parseInt;
myTest.myMethod("1");
3. Lambda 表達式比較典型的應用就是線程初始化
new Thread(new Runnable() {
@Override
public void run() {
System.out.println("原方式創建一個線程");
}
}).start();
使用Lambda表達式後,就可以簡化爲
new Thread(() -> System.out.println("使用Lambda表達式")).start();
實際工作中並不推薦顯示的創建一個線程,強烈建議使用線程池的方式創建線程,這裏只是提供一個示例。
4.Lambda表達式也可在集合使用 forEach 方法時使用,比如下面這個示例
List<Integer> list = Arrays.asList(0, 1, 2, 3, 4, 5, 6);
List<Integer> result = new ArrayList<>();
int min = 2;
list.forEach(i -> {
if (i > min) {
result.add(i);
}
});
result.forEach(System.out::println);
需要注意的是,Lambda表達式使用外部局部變量時,外部局部變量修飾符只能爲 final(如忽略不寫,編譯器會默認其爲 final 修飾),當你在 Lambda 表達式內部試圖修改外部局域變量時,會報錯
由於本人水平有限,難免有錯誤和疏漏,請不吝賜教.