java8-Lambda表示式介紹
阿新 • • 發佈:2018-12-18
簡介
Lambda,“語法糖”,是一個匿名函式,我們可以把Lambda表示式理解為是一個可以傳遞的程式碼(將程式碼像資料一樣進行傳遞)。可以寫出更簡潔、更靈活的程式碼。作為一種更緊湊的程式碼風格,使java的語言表達能力得到了提升。
為什麼使用Lambda表示式
可以以下程式碼
@Test public void test4(){ //使用匿名內部類 Comparator<Integer> comparator = new Comparator<>() { @Override public int compare(Integer o1, Integer o2) { return Integer.compare(o1,o2); } }; System.out.println(comparator.compare(2,3)); System.out.println("----------------------------------------"); //使用Lambda表示式 Comparator<Integer> handler = (x, y) -> Integer.compare(x, y); System.out.println( handler.compare(2,3)); }
輸出
-1
----------------------------------------
-1
從以上程式碼可以看出不使用Lambda表示式時,程式碼非常的繁瑣,隨著回撥模式和函數語言程式設計風格的日益流行,我們需要在Java中提供一種儘可能輕量級的將程式碼封裝為資料的方法。匿名內部類並不是一個好的選擇,因為: 1. 語法過於冗餘 2. 匿名內部類中this和變數名容易使人產生誤解 3. 型別載入和例項建立語義不夠靈活 java8解決了這些問題 因此你可以使用更少的程式碼來實現同樣的功能。
Lambda表示式的基礎語法
概念
在Java8中引入了一個新的操作符“->” 稱作箭頭操作符或Lambda表示式。 Lambda分為兩個部分
- 左側:Lambda表示式的引數列表
- 右側:Lambda表示式中所需執行的功能,即Lambda體
語法格式
- 無引數嗎,無返回值
()->System.out.println("hello world!");
- 有引數,並且無返回值
(x)->System.out.println(x);
- 若只有一個引數,則小括號可以省略不寫
x->System.out.println(x);
- 有兩個以上的引數,有返回值,並且Lambda體中有多條語句時
Comparator<Integer> con = (x,y)->{ System.out.println("函式式介面"); return Integer.compare(x,y); }
- 若Lambda表示式中只有一條語句時
Comparator<Integer> com =(x,y)->Integer.compare(x,y);
- Lambda 表示式的引數列表的引數型別可以省略不寫,因為JVM編譯器通過上下文推斷出資料型別,即型別推斷
Comparator<Integer> com=(Integer x,Integer y)->Integer.compare(x,y);
Comparator<Integer> com=(x,y)->Integer.compare(x,y);
注意
Lambda表示式需要“函式式介面”的支援 函式式介面:介面中只有一個抽象方法的介面稱為函式式介面,可以使用註解@FunctionalInterface來修飾,可以檢查是否是函式式介面
Java8內建的四大核心函式式介面
介紹
函式式介面 | 說明 | 引數型別 | 返回型別 | 內建方法 | 用途 |
---|---|---|---|---|---|
Consumer | 消費型介面 | T | void | void accept(T t) | 對型別T引數操作,無返回結果。 |
Supplier | 供給型介面 | 無 | T | T get() | 返回T型別引數。 |
Function | 函式型介面 | T | R | R apply(T t) | 對於型別T引數操作,返回R型別引數。 |
Predicate | 斷言型介面 | T | boolean | boolean test(T t) | 對型別T進行條件篩選操作,返回boolean. |
- Consumer 消費型介面
/**
* Consumer<T> 消費者型別介面 無返回值
*/
@Test
public void consumer(){
consumers("張三", new Consumer<String>() {
@Override
public void accept(String s) {
System.out.println(s+"去了北京天安門");
}
});
System.out.println("--------Lambda表示式--------");
consumers("李四",n-> System.out.println(n+"去了九寨溝"));
}
void consumers(String Name,Consumer<String> con){
con.accept(Name);
}
------------------輸出------------------
張三去了北京天安門
--------Lambda表示式--------
李四去了九寨溝
- Supplier 供給型介面
/**
* Supplier 供給型介面 T get();
*/
@Test
public void supplier(){
List<Integer> list1 = getNumList(5, new Supplier<Integer>() {
@Override
public Integer get() {
return (int) (Math.random() * 10);
}
});
list1.forEach(System.out::println);
System.out.println("--------Lambda表示式--------");
List<Integer> list = getNumList(5,()->(int)(Math.random()*100));
list.forEach(System.out::println);
}
List<Integer> getNumList(int num , Supplier<Integer> sup){
List<Integer> list = new ArrayList<>();
for (int i=0; i<num; i++){
Integer n = sup.get();
list.add(n);
}
return list;
}
-----------------輸出------------------
3
3
0
1
8
--------Lambda表示式--------
21
5
92
69
69
- Function 函式型介面
/**
* Function<T,R> 函式型介面 R apply(T t);
*/
@Test
public void function(){
String s = handle("hjkwegfkGHJKjksagdhfjklgwhejf", new Function<String, String>() {
@Override
public String apply(String s) {
return s.toUpperCase();
}
});
System.out.println(s);
System.out.println("--------Lambda表示式--------");
String s2 = handle("hdjagshjgquga", s1 -> s1.toUpperCase());
System.out.println(s2);
}
String handle(String str, Function<String,String> f){
return f.apply(str);
}
--------------輸出--------------------
HJKWEGFKGHJKJKSAGDHFJKLGWHEJF
--------Lambda表示式--------
HDJAGSHJGQUGA
- Predicate 斷言型介面
/**
* Predicate 斷言型介面 boolean test(T t)
*/
@Test
public void predicate(){
List<Integer> list = Arrays.asList(10, 9, 20, 31, 21, 42);
//如果數大於18就加入新的集合中
List<Integer> filter = filter(list, new Predicate<Integer>() {
@Override
public boolean test(Integer integer) {
return integer > 18;
}
});
filter.forEach(System.out::println);
System.out.println("--------Lambda表示式--------");
List<Integer> f = filter(list, x -> x > 18);
f.forEach(System.out::println);
}
List<Integer> filter(List<Integer> list, Predicate<Integer> p){
List<Integer> list1 = new ArrayList<>();
for (Integer integer : list) {
if(p.test(integer)){
list1.add(integer);
}
}
return list1;
}
-----------------------輸出-----------------
20
31
21
42
--------Lambda表示式--------
20
31
21
42
其他延申函式式介面
函式式介面 | 引數型別 | 返回型別 | 內建方法 | 用途 |
---|---|---|---|---|
BiFunction | T,U | R | R apply(T t,U u) | 對型別T,U引數進行操作,返回R型別結果 |
UnaryOperator | T | T | T apply(T t) | 對型別T物件進行一元運算,並返回T型別的結果 |
BinaryOperator | T,T | T | T apply(T t1,T t2) | 對型別T物件進行二元運算,並返回T型別的結果 |
BiConsumer | T,U | void | void accept(T t,U u) | 對型別T,U引數進行操作 |
ToIntFunction /ToLongFunction / ToDoubleFuction | T | int,long,double | int applyAsInt(T value)/ long applyAsLong(T value) /double applyAsDouble(T value) | 分別計算int,long,double值 |
IntFunction /LongFunction / DoubleFuction | int,long,double | R | R apply(int value)/R apply(longvalue) /R apply(double value) | 引數分別是int,long,double型別函式 |
方法引用
若Lambda體中的功能已經有方法提供了實現,可以使用方法引用(可以將方法引用理解為Lambda表示式的另外一種表現形式)
基本的引用
- 物件::例項方法
User u =new User();
u::getName
- 類名::靜態方法名
Comparator<Integer> handler = Integer::compare;
- 類名::例項方法名
User::getName
注意
- 方法引用所引用的方法的引數列表與返回值型別,需要與函式式介面中的抽象方法的引數列表和返回值保持一致
- 若Lambda的引數列表的第一引數,是例項方法的呼叫者,第二個引數(或無參)是例項方法的引數時,格式為ClassName::MethodName
擴充套件
- 構造器引用 構造器的引數列表需要與函式式介面中的引數列表保持一致 類名::new
User::new
- 陣列引用 型別[]::new
Integer[]::new