Lambda 表達式能夠理解爲簡潔地表示可傳遞的匿名函數的一種方式:它沒有名稱,但它有參數列表、函數主體、返回類型,可能還有一個能夠拋出的異常列表。java
So That:ide
Lambda 表達式是一個匿名函數(對於 Java 而言並不很準確,但這裏咱們不糾結這個問題)。簡單來講,這是一種沒有聲明的方法,即沒有訪問修飾符,返回值聲明和名稱。函數
Java 中的 Lambda 表達式一般使用語法是 (argument) -> (body)
:spa
(arg1, arg2...) -> { body }
(type1 arg1, type2 arg2...) -> { body }
複製代碼
Lambda 表達式舉例:code
(int a, int b) -> { return a + b; }
() -> System.out.println("Hello World");
(String s) -> { System.out.println(s); }
() -> 42
() -> { return 3.1415 };
複製代碼
Lambda 表達式由參數列表、箭頭和 Lambda 主體組成。cdn
(Apple o1, Apple o2) -> Integer.valueOf(o1.getWeight()).compareTo(Integer.valueOf(o2.getWeight()))
複製代碼
1)Lambda 表達式的結構對象
(int a)
與剛纔相同 (a)
。(a, b)
或 (int a, int b)
或 (String a, int b, float c)
。() -> 42
。a -> return a*a
。2)有效Lambda 表達式舉例blog
Lambda 表達式 | 含義 |
---|---|
(String s) -> s.length() |
表達式具備一個 String 類型的參數並返回一個 int。 Lambda 沒有 return 語句,由於已經隱含的 return,能夠顯示調用 return。 |
(Apple a) -> a.getWeight() > 150 |
表達式有一個 Apple 類型的參數並返回一個 boolean 值 |
(int x, int y) -> { System.out.printn("Result"); System.out.printn(x + y)} |
表達式具備兩個 int 類型的參數而沒有返回值(void返回),Lambda 表達式能夠包含多行語句,但必需要使用大括號包起來。 |
() -> 42 |
表達式沒有參數,返回一個 int 類型的值。 |
(Apple o1, Apple o2) -> Integer.valueOf(o1.getWeight()) .compareTo (Integer.valueOf(o2.getWeight())) |
表達式具備兩個 Apple 類型的參數,返回一個 int 比較重要。 |
3)Lambda 表達式的使用舉例接口
使用案例 | Lambda 示例 |
---|---|
布爾表達式 | (List<String> list) -> list.isEmpty() |
建立對象 | () -> new Apple(10) |
消費對象 | (Apple a) -> { System.out.println(a.getWeight) } |
從一個對象中選擇/抽取 | (String s) -> s.lenght() |
組合兩個值 | (int a, int b) -> a * b |
比較兩個對象 | ``(Apple o1, Apple o2) -><br> Integer.valueOf(o1.getWeight())<br> .compareTo(Integer.valueOf(o2.getWeight()))` |
函數式接口就是隻定義一個抽象方法的接口,好比 Java API 中的 Predicate、Comparator 和 Runnable 等。圖片
public interface Predicate<T> {
boolean test(T t);
}
public interface Comparator<T> {
int compare(T o1, T o2);
}
public interface Runnable {
void run();
}
複製代碼
函數式接口做用是什麼?
Lambda 表達式容許你直接之內聯的形式爲函數式接口的抽象方法提供實現,並把整個表達式做爲函數式接口的實例(具體說來,是函數式接口一個具體實現 的實例)。你用匿名內部類也能夠完成一樣的事情,只不過比較笨拙:須要提供一個實現,而後 再直接內聯將它實例化。
下面的代碼是有效的,由於Runnable是一個只定義了一個抽象方法run 的函數式接口:
//使用Lambda
Runnable r1 = () -> System.out.println("Hello World 1");
//匿名類
Runnable r2 = new Runnable(){
public void run(){
System.out.println("Hello World 2");
}
};
public static void process(Runnable r){
r.run();
}
process(r1); //打印 "Hello World 1"
process(r2); //打印 "Hello World 2"
//利用直接傳遞的 Lambda 打印 "Hello World 3"
process(() -> System.out.println("Hello World 3"));
複製代碼
1)以前作法
Comparator<Apple> byWeight = new Comparator<Apple>() {
public int compare(Apple a1, Apple a2){
return a1.getWeight().compareTo(a2.getWeight());
}
};
複製代碼
2)如今作法
Comparator<Apple> byWeight =
(Apple a1, Apple a2) -> a1.getWeight().compareTo(a2.getWeight());
複製代碼
3)再經過一個明顯的實例
public static void rawUseMethod(){
List<String> names = Arrays.asList("peter", "anna", "mike", "xenia");
Collections.sort(names, new Comparator<String>() {
@Override
public int compare(String a, String b) {
return a.compareTo(b);
}
});
for (String str : names){
System.out.println(str);
}
}
public static void useLambda1(){
List<String> names = Arrays.asList("peter", "anna", "mike", "xenia");
Collections.sort(names,(String a,String b) -> {
return a.compareTo(b);
});
for (String str : names){
System.out.println(str);
}
}
public static void useLambda2(){
List<String> names = Arrays.asList("peter", "anna", "mike", "xenia");
Collections.sort(names,(String a,String b) -> a.compareTo(b));
for (String str : names){
System.out.println(str);
}
}
public static void useLambda3(){
List<String> names = Arrays.asList("peter", "anna", "mike", "xenia");
names.sort((String a,String b) -> a.compareTo(b));
//固然也能夠直接去掉參數類型,直接推導出來便可
names.sort((a,b) -> a.compareTo(b));
for (String str : names){
System.out.println(str);
}
}
複製代碼
爲了進一步說明,下面給出了Java 8中五個有效的Lambda表達式的例子。
布爾表達式 | (List list) -> list.isEmpty() |
---|---|
建立對象 | () -> new Apple(10) |
消費一個對象 | (Apple a) -> { System.out.println(a.getWeight()); } |
從一個對象中選擇/抽取 | (String s) -> s.length() |
組合兩個值 | (int a, int b) -> a * b |
比較兩個對象 | (Apple a1, Apple a2) -> a1.getWeight().compareTo(a2.getWeight()) |
"函數式接口"是指僅僅只包含一個抽象方法的接口,每個函數式接口類型的lambda表達式都自動被匹配到這個抽象方法。由於 默認方法 不算抽象方法,因此你也能夠給你的函數式接口添加默認方法。
咱們能夠將lambda表達式看成任意只包含一個抽象方法的接口類型,爲了確保你的接口確實是達到這個要求的,能夠接口上添加 @FunctionalInterface 註解,編譯器若是發現你標註了這個註解的接口有多於一個抽象方法的時候會報錯的。
1)定義函數式接口
//這個註解不加也能夠,加上只是爲了讓編譯器檢查
@FunctionalInterface
interface Action{
public void run();
default void doSomething(){
System.out.println("doSomething..");
}
}
//這個註解不加也能夠,加上只是爲了讓編譯器檢查
@FunctionalInterface
interface Work<T,V>{
public V doWork(T t);
}
複製代碼
2)使用
public class LambdaTest2 {
public static void main(String[] args) {
//原來的內部類實現方式
test(new Action(){
@Override
public void run() {
System.out.println("run..");
}
});
//lambda表達式方法
test(()->System.out.println("run"));
//也能夠先建立對象
Action a = ()->System.out.println("run...");
System.out.println(a.getClass());
test(a);
//接口中有泛型也能夠,只關注方法的參數和返回值
Work<String,Integer> w = (v)->v.length();
run(w);
run((v)->v.length());
//若是參數只有一個,那麼還能夠這樣簡寫: 去掉小括號
//注意代碼就一句,做爲返回值的話不用寫return
run(v->v.length());
//有多句代碼,就須要寫{}了,而且須要寫return
run(v->{
System.out.println("doWork..");
return v.length();
});
//觀察下面代碼是什麼意思
run(v->1);
}
public static void test(Action a){
a.run();
a.doSomething();
}
public static void run(Work<String,Integer> a){
int i = a.doWork("hello");
System.out.println(i);
}
}
複製代碼
注意:
lambda表達式沒法訪問接口的默認方法,lambda表達式只能去匹配對應接口中的惟一抽象方法。
至關於lambda表達式只是對抽象方法的實現,並無建立接口的實現類對象,由於咱們只是想使用這個抽象方法的實現。