一文掌握 JAVA8新特性

一文掌握 JAVA8新特性

一、新特性概覽

在這裏插入圖片描述

●速度更快
●代碼更少(增加了新的語法: Lambda 表達式
●強大的Stream API
●便於並行
●最大化減少空指針異常: Optional
●Nashorn引擎,允許在JVM上運行JS應用

並行流與串行流
並行流就是把一個內容分成多個數據塊,並用不同的線程分別處理每個數據塊的流。相比較串行的流,並行的流可以很大程度上提高程序的執行效率。
Java 8中將並行進行了優化,我們可以很容易的對數據進行並行操作。Stream API可以聲明性地通過parallel()與sequential() 在並行流與順序流之間進行切換。

二、Lambda表達式應用舉例

Lambda是一 個匿名函數,我們可以把Lambda表達式理解爲是一 段可以
傳遞的代碼(將代碼像數據“ 樣進行傳遞)。使用它可以寫出更簡潔、更
靈活的代碼。作爲一種更緊湊的代碼風格,使Java的語言表達能力得到了

image-20200624164745895

lambda表達式寫法

image-20200624164935369

image-20200624165223301

lambda表達式寫法

image-20200624165523236

可以看見,Lambda表達式更簡潔了

具體說明:

* 1.舉例 (o1,o2) -> Integer.compare(o1,o2);
* 2.格式
*      -> :lambda操作符 或 箭頭操作符
*      ->左邊:lambda形參列表 (其實就是接口中的抽象方法的形參列表)
*      ->右邊:lambda體(其實就是重寫的抽象方法的方法體)
* 3.lambda表達式的使用: (分爲6種情況)
1.無參,無返回值

image-20200624171136657

lambda表達式的本質:作爲接口的實例

2.lambda需要一個參數,但是沒有返回值

image-20200624171820261

3.數據類型可以省略,因爲可由編譯器推斷出,稱爲“類型推斷”

image-20200624172250834

4.lambda若只需要一個參數時,參數的小括號可以省略

image-20200624173712745

5.lambda需要兩個或以上的參數,多條執行語句,並且可以有返回值

image-20200624174420737

6.當lambda體只有一條語句時,return與大括號若有,都可以省略

image-20200624174836729

三、函數式(Functional)接口

lambda表達式的本質:作爲函數式接口的實現

函數式接口:

@FunctionalInterface加不加都可以,只是一個校驗。跟@Override一樣

image-20200624180309264

image-20200624175948246

●只包含一個抽象方法的接口,稱爲函數式接口。
●你可以通過Lambda表達式來創建該接口的對象(若Lambda表達式拋出一個受檢異常(即:非運行時異常),那麼該異常需要在目標接口的抽象方法上進行聲明)
●我們可以在一 個接口上使用**@FunctionalInterface**註解,這樣做可以檢查它是否是一個函數式接口。同時javadoc也會包含–條聲明,說明這個接口是一個函數式接口。
●在java.util.function包下定義了Java 8的豐富的函數式接口

如何理解函數式接口

●Java從誕生日起就是一-直倡導“一切皆對象”,在Java裏面面向對象(OOP)編程是一切。即java不但可 以支持OOP還可以支持OOF (面向函數編程)
●在函數式編程語言當中,函數被當做一等公民對待。 在將函數作爲一 等公民的編程語言中,Lambda表達式的類型是函數。但是在Java8中,有所不同。在Java8中,Lambda表達式是對象,而不是函數,它們必須依附於一類特別的對象類型——函數式接口。
●簡單的說,在Java8中,Lambda表達式就是一個函數式接口的實例。這就是Lambda表達式和函數式接口的關係。也就是說,只要一個對象是函數式接口的實例,那麼該對象就可以用Lambda表達式來表示。
●所以以前用匿名實現類表示的現在都可以用Lambda表達式來寫。

image-20200624181226234

* 消費型接口 Consumer<T>    void accept(T t) 消費這個t
* 供給型接口 Supplier<T>    T get() 不給東西,返回一個東西。供給
* 函數型接口 Function<T,R>  R apply(T t)給一個T類型的,返回R類型
* 斷定型接口 Predicate<T>   boolean test(T t)根據這個T來判斷truefalse

四個基本的。來寫兩個例子看一下

image-20200624191817938

image-20200624192807711

其他接口

image-20200624192935815

四、方法引用與構造器引用

方法引用

●當要傳遞給ambda體的操作,已經有實現的方法了,可以使用方法引用!
●方法引用可以看做是Lambda表達式深層次的表達。換句話說,方法引用就是Lambda表達式,也就是函數式接口的一個實例,通過方法的名字來指向一個方法,可以認爲是Lambda表達式的一個語法糖。
●要求:實現接口的抽象方法的參數列表和返回值類型,必須與方法引用的方法的參數列表和返回值類型保持一致!
●格式:使用操作符**“::”**將類(或對象)與方法名分隔開來。
●如下三種主要使用情況:
➢對象::實例方法名
➢類::靜態方法名
➢類::實例方法名

我們來用代碼看一下:
準備

image-20200624193705458

Employee,寫了一些成員及方法

image-20200624193749753

EmployData,用於生成一些測試數據

image-20200624193901102

測試

1.對象::實例方法

image-20200624200306887

image-20200624200825552
2.類::靜態方法

image-20200624201655879

image-20200624201840108

3.類::非靜態方法

image-20200624203215022

image-20200625085359717

image-20200625085415451

總結
* 方法引用的使用
* 1.使用情景:當要傳遞給lambda體的操作,已經有實現的方法了,可以使用方法引用
* 2.方法引用,本質上就是lambda表達式,二lambda表達式作爲函數式接口的實例,所以
*   方法引用,也是函數式接口的實現
* 3.使用格式: 類(或對象) ::  方法名
* 4.具體分爲如下三種情況
*  情況1    對象 :: 非靜態方法
*  情況2:: 靜態方法
*  情況3:: 非靜態方法 (!!)
* 5.方法引用使用的要求:要i去接口中的抽象方法的形參列表喝返回值裏欸性能關於方法引用的方法
*   的形參列表喝返回值相同。(針對於情況1,情況2)比如下面的這個void accept(T t)*   void println(T t)

構造器引用

1.空參構造器

image-20200625085858346

2.有參構造器

image-20200625090228413

image-20200625090627281

數組引用

image-20200625091210979

五、Stream API

●Java8中有兩大最爲重要的改變。第一一個是Lambda表達式;另外一 -個則是Stream API。
●Stream是Java8中處理集合的關鍵抽象概念,它可以指定你希望對集合進行的操作,可以執行非常複雜的查找、過濾和映射數據等操作。**使用Stream API對集合數據進行操作,就類似於使用SQL執行的數據庫查詢。**也可以使用Stream API來並行執行操作。簡言之StreamAPl 提供了一種高效且易於使用的處理數據的方式。

爲什麼要使用Stream API
●實際開發中,項目中多數數據源都來自於Mysql, Oracle等。 但現在數據源可以更多了,有MongDB,Radis等, 而這些NoSQL的數據就需要Java層面去處理。
●Stream 和Collection集合的區別: Collection 是一種靜態的內存數據結構,而Stream是有關計算的。前者是主要面向內存,存儲在內存中,後者,主要是面向CPU,通過CPU實現算。

集合講的是數據,stream講的是運算

注意:
①Stream自己不會存儲元素。
②Stream不會改變源對象。相反,他們會返回一一個持有結果的新Stream.
③Stream操作是延遲執行的。這意味着他們會等到需要結果的時候才執行。

image-20200625092325628

創建Stream

我們接着用上面的EmployData.getEmployees()來得到一個list

image-20200625092952341

一、通過集合

Java8中的Collection 接口被擴展,提供了兩個獲取流
的方法:
●default Stream<E> stream() :返回一個順序流
●default Stream<E> parallelStream():返回一個並行流

我們來看一下這個stream

image-20200625093252411

代碼:

image-20200625093416073

集合是一種容器,數組也是

二、通過數組

Java8中的Arrays的靜態方法stream()可以獲取數組流:
●static <T> Stream<T> stream(T[] array):返回一個流
重載形式,能夠處理對應基本類型的數組:
●public static IntStream stream(int[] array)
●public static LongStream stream(long[] array)
●public static DoubleStream stream(double[] array)

image-20200625094730656

三、通過Stream的of()

可以調用Stream類靜態方法of(), 通過顯示值創建一個流。它可以接收任意數量的參數。
●public static<T> Stream<T> of(T… values):返回一個流

image-20200625095933299

四、創建無限流(用的比較少)

可以使用靜態方法Stream.iterate()和Stream.generate(),
創建無限流。
迭代
public static<T> Stream<T> iterate(final T seed, final UnaryOperator<T> f)
生成
public static<T> Stream<T> generate(Supplier<T> s)

image-20200625101251827

image-20200625101307875

可以看見 **UnaryOperator繼承了Fucntion,**Function中的apply是

image-20200625101410685

接受一個T,返回一個R,而UnaryOperator比較特殊,接受一個T,返回一個T

image-20200625101449804

image-20200625101917035

終止操作就是System.out.println,用於消費

Stream的中間操作

image-20200625101950648

一、篩選與切片

首先看一下之前Employee中重寫的hashCode跟equals。用於distinct演示

image-20200625103740053

image-20200625104342217

image-20200625104403904

二、映射

image-20200625104529920

image-20200625110202738

接下來看flatMap,這個有點麻煩,我們先看一下這個

有add跟addAll,我們通過這兩個來類比flatMap

add

image-20200625110505163

addAll

image-20200625110530062

即flatMap相當於addAll

map

image-20200625112005114

flatMap

image-20200625112252531

三、排序

image-20200625112433062

sorted()

image-20200625112731800

sorted(Comparator conn)

image-20200625113330328

Stream終止操作

一、查找與匹配

image-20200625113434789

image-20200625143634348

二、歸約

image-20200625143734182

reduce(T iden,BinaryOperator b)

reduce

image-20200625144135570

BinaryOperator

image-20200625144236916

Integer.sum

image-20200625144323921

identity是初始值

image-20200625150522087

這裏(d1,d2)->d1+d2,爲什麼呢?
image-20200625150602922

image-20200625150615548

image-20200625150633836

三、收集

image-20200625150713239

image-20200625150916768

image-20200625151914701

下面僅對list跟set做一個演示

image-20200625151936763

六、Optional類

●到目前爲止,臭名昭著的空指針異常是導致Java應用程序失敗的最常見原因。以前,爲了解決空指針異常,Google公 司著名的Guava項目引入了Optional類,Guava通過使用檢查空值的方式來防止代碼污染,它鼓勵程序員寫更乾淨的代碼。受到Google Guava的啓發Optional類 已經成爲Java 8類庫的一部分。)

●Optional<T>類(java.util.Optional) 是-一個容器類,它可以保存類型T的值,代表這個值存在。或者僅僅保存null,表示這個值不存在。原來用null表示一個值不存在,現Optional可以更好的表達這個概念。並且可以避免空指針異常。
●Optional類的Javadoc描述如下:這是一個可以爲null的容器對象。如果值存在則isPresent()方法會返回true,調用get()方法 會返回該對象。

image-20200625152253989

準備:

image-20200625152604205

image-20200625152611828

下面舉幾個例子

1.Optional.of

image-20200625153016669

image-20200625153030589

2.Optional.ofNullable

image-20200625153208180

image-20200625153220631

3.我們來看一下使用舉例

image-20200625153443806

在平常的開發中,我們經常遇到上面這樣的空指針異常

那麼我們優化後呢?

image-20200625153703777

那麼我們用 Optional來怎麼實現

image-20200625154650333

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章