Java8新特性-Lambda表達(dá)式詳解
一、簡介
Java 8 (又稱為 jdk 1.8) 是 Java 語言開發(fā)的一個(gè)主要版本。 Oracle 公司于 2014 年 3 月 18 日發(fā)布 Java 8 ,它支持函數(shù)式編程,新的 JavaScript 引擎,新的日期 API,新的Stream API 等。
特征
- 可選類型聲明:不需要聲明參數(shù)類型,編譯器可以統(tǒng)一識別參數(shù)值。
- 可選的參數(shù)圓括號:一個(gè)參數(shù)無需定義圓括號,但多個(gè)參數(shù)需要定義圓括號。
- 可選的大括號:如果主體包含了一個(gè)語句,就不需要使用大括號。
- 可選的返回關(guān)鍵字:如果主體只有一個(gè)表達(dá)式返回值則編譯器會自動返回值,大括號需要指定表達(dá)式返回了一個(gè)數(shù)值。
注意:Lambda表達(dá)式適用于只有一個(gè)抽象方法的接口!!
引入
自定義接口
interface Fu{
void add();
}使用匿名內(nèi)部類實(shí)現(xiàn)接口
Fu fu = new Fu() {
@Override
public void add() {
System.out.println("我是add方法");
}
};
fu.add();使用Lambda表達(dá)式實(shí)現(xiàn)接口
Fu fu1 = ()->{
System.out.println("我是add1方法");
};
fu1.add();Lambda表達(dá)式的總結(jié)
- Lambda表達(dá)式基于數(shù)學(xué)中的 入 演化得名的,對應(yīng)Java中的lambda抽象,是一個(gè)匿名函數(shù),就是沒有函數(shù)名的函數(shù)。
- 好處
- 使代碼更加簡潔緊湊,且可與Stream API等相結(jié)合,Lambda表達(dá)式經(jīng)常代替匿名內(nèi)部類使用
- 語法
- (參數(shù))->表達(dá)式或者(參數(shù))->{語句體;}
- 參數(shù):要重寫方法的參數(shù)列表
- ->:Lambda表達(dá)式的運(yùn)算符
- 表達(dá)式或語句體:要實(shí)現(xiàn)的方法的方法體
- 本質(zhì)
- 是一種匿名函數(shù)(不是匿名內(nèi)部類),簡單說,它沒有聲明的方法、沒有訪問修飾符、返回值聲明和名字,它是屬于函數(shù)式編程的概念
三、Lambda表達(dá)式的使用
無參、無返回值
接口
interface F{
void add();
}測試
//無參無返回值
F f = ()->{
System.out.println("我是add方法");
};
f.add();有參無返回值
接口
interface F{
void add(int a);
}測試
F f = (int a)->{
System.out.println("a="+a);
};
f.add(12);無參數(shù)有返回值
接口
interface F{
int add();
}測試
F f = ()->{
return 12;
};
int i = f.add();
System.out.println(i);有參數(shù)有返回值
接口
interface F{
int add(int a);
}測試
F f = (int a)->{
return 12+a;
};
int i = f.add( 12 );
System.out.println(i);四、Lambda表達(dá)式的注意事項(xiàng)
- Lambda表達(dá)式中 () 的參數(shù)類型可以省略 (int a,int b)==>(a,b)
- 接口中如果只有一個(gè)參數(shù),Lambda表達(dá)式中 () 可以省略 (int a)==> (a)==>a
- 如果方法體中只有一條執(zhí)行語句時(shí) 外層的 {} 可以省略
- 如果方法體中只有一條返回語句,{}和return 都可以省略
五、函數(shù)式接口
函數(shù)式接口(Functional Interface)就是一個(gè)有且僅有一個(gè)抽象方法,可以有其他普通方法,用@FunctionalInterface檢驗(yàn)是否是函數(shù)式接口。
@FunctionalInterface
interface F1{
void t1();
default void t2(){//不計(jì)
}
static void t3(){//不計(jì)
}
public boolean equals(Object object);//不計(jì)
}作用:在Java中主要用在Lambda表達(dá)式和方法引用。
內(nèi)置函數(shù)式接口
- Consumer<T>:消費(fèi)型接口(void accept(T t))。有參數(shù),無返回值
- Supplier<T>:供給型接口(T get())。有參數(shù),無返回值
- Function<T,R>:函數(shù)型接口(R apply(T t))。一個(gè)輸入?yún)?shù),一個(gè)輸出參數(shù),兩種類型可以一致,也可以不一致
- Predicate<T>:斷言型接口(boolean test(T t))。輸入一個(gè)參數(shù),輸出一個(gè)boolean類型的返回值
函數(shù)式接口使用場景
消費(fèi)型接口
//函數(shù)式接口的使用場景
public class Test03 {
public static void main(String[] args) {
List<Integer> list = new ArrayList<>();
Collections.addAll(list,1,2,3,6,5,4,8,9);
//匿名內(nèi)部類
Consumer<Integer> con = new Consumer<Integer>() {
@Override
public void accept(Integer integer) {
//參數(shù)代表集合中的每一個(gè)數(shù)據(jù)
System.out.print(integer+" ");
}
};
list.forEach( con );
System.out.println();
System.out.println("==================");
//Lambda表達(dá)式1
Consumer cons = (y)->{
System.out.print(y+" ");
};
list.forEach( cons );
System.out.println();
System.out.println("==================");
//Lambda表達(dá)式2
list.forEach( y-> System.out.print(y+" ") );
}
}斷言型接口
public class Test04 {
public static void main(String[] args) {
List<Integer> list = new ArrayList<>();
Collections.addAll(list,1,2,3,6,5,4,8,9);
//匿名內(nèi)部類
Predicate<Integer> predicate = new Predicate<Integer>() {
@Override
public boolean test(Integer integer) {
//參數(shù)o代表集合中的每一個(gè)數(shù)
if (integer<=6){
return true;//刪除該數(shù)據(jù)
}
return false;//不刪除該數(shù)據(jù)
}
};
list.removeIf(predicate);
list.forEach( x-> System.out.println(x) );
System.out.println("=================");
//Lambda表達(dá)式
list.removeIf( y->{
if (y<=6){
return true;
}
return false;
} );
list.removeIf(predicate);
list.forEach( x-> System.out.println(x) );
System.out.println("=================");
}
}六、方法調(diào)用
方法引用通過方法的名字來指向一個(gè)方法。方法引用可以使語言的構(gòu)造更緊湊簡潔,減少冗余代碼。方法引用使用一對冒號 :: 。
//方法引用
public class Test05 {
public static void main(String[] args) {
List<Integer> list = new ArrayList<>();
Collections.addAll(list,4,8,9);
//使用Lambda表達(dá)式
list.forEach( x-> System.out.println(x) );
System.out.println("==================");
//方法引用
//使用場景,參數(shù)傳遞過來不做任何處理,直接輸出的就可以使用方法引用
list.forEach(System.out::println);
}
}構(gòu)造器引用:它的語法是Class::new,或者更一般的Class< T >::new
final Car car = Car.create( Car::new ); final List< Car > cars = Arrays.asList( car );
靜態(tài)方法引用:它的語法是Class::static_method
cars.forEach( Car::collide );
特定類的任意對象的方法引用:它的語法是Class::method
cars.forEach( Car::repair );
特定對象的方法引用:它的語法是instance::method
final Car police = Car.create( Car::new ); cars.forEach( police::follow );
七、Stream流式編程
什么是 Stream?
Stream(流)是一個(gè)來自數(shù)據(jù)源的元素隊(duì)列并支持聚合操作
- 元素是特定類型的對象,形成一個(gè)隊(duì)列。 Java中的Stream并不會存儲元素,而是按需計(jì)算。
- 數(shù)據(jù)源 流的來源。 可以是集合,數(shù)組,I/O channel, 產(chǎn)生器generator 等。
- 聚合操作 類似SQL語句一樣的操作, 比如filter, map, reduce, find, match, sorted等。
和以前的Collection操作不同, Stream操作還有兩個(gè)基礎(chǔ)的特征:
- Pipelining: 中間操作都會返回流對象本身。 這樣多個(gè)操作可以串聯(lián)成一個(gè)管道, 如同流式風(fēng)格(fluent style)。 這樣做可以對操作進(jìn)行優(yōu)化, 比如延遲執(zhí)行(laziness)和短路( short-circuiting)。
- 內(nèi)部迭代: 以前對集合遍歷都是通過Iterator或者For-Each的方式, 顯式的在集合外部進(jìn)行迭代, 這叫做外部迭代。 Stream提供了內(nèi)部迭代的方式, 通過訪問者模式(Visitor)實(shí)現(xiàn)。
使用 Stream流的步驟
- 創(chuàng)建Stream:從一個(gè)數(shù)據(jù)源(集合、數(shù)組)中獲取
- 中間操作:一個(gè)操作的中間鏈,對數(shù)據(jù)源的數(shù)據(jù)進(jìn)行處理
- 終止操作:一個(gè)終止操作,執(zhí)行中間操作鏈,并產(chǎn)生結(jié)果
排序去重
//Stream 流式編程
public class StreamTest01 {
public static void main(String[] args) {
//需求:有一堆數(shù)據(jù),且有重復(fù)值,要求有序去除重復(fù)值
List<Integer> list = new ArrayList<>();
Collections.addAll(list,56,89,75,64,24,25,24,89,56,75);
//流式編程處理
//獲取stream
Stream<Integer> stream = list.stream();
//中間操作
stream = stream.distinct()//去重操作
.sorted();//排序
//終止操作
stream.forEach( x->{//輸出集合中元素
System.out.println(x);
} );
}
}中間操作
stream = stream.distinct()//去重操作
.sorted();//排序
.limit( 4 );//取前四個(gè)元素
.skip( 2 );//跳過前幾個(gè)元素
.map( x->x+4 );//每一個(gè)元素加上特定的值
.filter( x->{//過濾操作,true正常返回,false不返回
if (x>=25){
return true;
}
return false;
} );八、串行流和并行流
串行流
Stream<Integer> stream = list.stream();//串行流
并行流
Stream<Integer> stream1 = list.parallelStream();//并行流
九、Optional 類
- Optional 類是一個(gè)可以為null的容器對象。如果值存在則isPresent()方法會返回true,調(diào)用get()方法會返回該對象。
- Optional 是個(gè)容器:它可以保存類型T的值,或者僅僅保存null。Optional提供很多有用的方法,這樣我們就不用顯式進(jìn)行空值檢測。
- Optional 類的引入很好的解決空指針異常。
Optional 類的方法
- static <T> Optional<T> empty() 返回空的 Optional 實(shí)例。
- boolean equals(Object obj) 判斷其他對象是否等于 Optional。
- Optional<T> filter(Predicate<? super <T> predicate) 如果值存在,并且這個(gè)值匹配給定的 predicate,返回一個(gè)Optional用以描述這個(gè)值,否則返回一個(gè)空的Optional。
- <U> Optional<U> flatMap(Function<? super T,Optional<U>> mapper) 如果值存在,返回基于Optional包含的映射方法的值,否則返回一個(gè)空的Optional
- T get() 如果在這個(gè)Optional中包含這個(gè)值,返回值,否則拋出異常:NoSuchElementException
- int hashCode() 返回存在值的哈希碼,如果值不存在 返回 0。
- void ifPresent(Consumer<? super T> consumer) 如果值存在則使用該值調(diào)用 consumer , 否則不做任何事情。
- boolean isPresent() 如果值存在則方法會返回true,否則返回 false
- <U>Optional<U> map(Function<? super T,? extends U> mapper) 如果有值,則對其執(zhí)行調(diào)用映射函數(shù)得到返回值。如果返回值不為 null,則創(chuàng)建包含映射返回值的Optional作為map方法返回值,否則返回空Optional。
- static <T> Optional<T> of(T value) 返回一個(gè)指定非null值的Optional。
- static <T> Optional<T> ofNullable(T value) 如果為非空,返回 Optional 描述的指定值,否則返回空的 Optional。
- T orElse(T other) 如果存在該值,返回值, 否則返回 other。
- T orElseGet(Supplier<? extends T> other) 如果存在該值,返回值, 否則觸發(fā) other,并返回 other 調(diào)用的結(jié)果。
- <X extends Throwable> T orElseThrow(Supplier<? extends X> exceptionSupplier) 如果存在該值,返回包含的值,否則拋出由 Supplier 繼承的異常
- String toString() 返回一個(gè)Optional的非空字符串,用來調(diào)試
以上就是Java8新特性-Lambda表達(dá)式詳解的詳細(xì)內(nèi)容,更多關(guān)于Java Lambda表達(dá)式的資料請關(guān)注腳本之家其它相關(guān)文章!
- 一文帶你看懂Java8中的lambda表達(dá)式和方法引用
- java8新特性-lambda表達(dá)式入門學(xué)習(xí)心得
- java8中的lambda表達(dá)式簡介
- Java8?lambda表達(dá)式的10個(gè)實(shí)例講解
- 詳解Java8如何使用Lambda表達(dá)式進(jìn)行比較
- Java8新特性:lambda表達(dá)式總結(jié)
- java8 forEach結(jié)合Lambda表達(dá)式遍歷 List操作
- Java8 用Lambda表達(dá)式給List集合排序的實(shí)現(xiàn)
- Java8中的Lambda表達(dá)式理解與使用示例詳解
相關(guān)文章
java 實(shí)現(xiàn)多線程的方法總結(jié)
這篇文章主要介紹了java 實(shí)現(xiàn)多線程的方法總結(jié)的相關(guān)資料,需要的朋友可以參考下2016-10-10
Dom4j解析XML_動力節(jié)點(diǎn)Java學(xué)院整理
這篇文章主要介紹了Dom4j解析XML,dom4j是一個(gè)Java的XML API,類似于jdom,用來讀寫XML文件的,有興趣的可以了解一下2017-07-07
Java?spring?MVC環(huán)境中實(shí)現(xiàn)WebSocket的示例代碼
這篇文章主要介紹了Java?spring?MVC環(huán)境中實(shí)現(xiàn)WebSocket,本文通過示例代碼給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2023-09-09
Java8 自定義CompletableFuture的原理解析
這篇文章主要介紹了Java8 自定義CompletableFuture的原理解析,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2021-11-11
SpringCloud使用Feign實(shí)現(xiàn)遠(yuǎn)程調(diào)用的使用示例
Feign是一個(gè)基于注解的HTTP客戶端庫,它允許您將HTTP請求轉(zhuǎn)換為聲明式的Java接口,本文主要介紹了SpringCloud使用Feign實(shí)現(xiàn)遠(yuǎn)程調(diào)用的使用示例,感興趣的可以了解一下2023-09-09
Java Hibernate中使用HQL語句進(jìn)行數(shù)據(jù)庫查詢的要點(diǎn)解析
HQL是Hibernate框架中提供的關(guān)系型數(shù)據(jù)庫操作腳本,當(dāng)然我們也可以使用原生的SQL語句,這里我們來看一下在Java Hibernate中使用HQL語句進(jìn)行數(shù)據(jù)庫查詢的要點(diǎn)解析:2016-06-06

