Java8新特性實踐
簡介
Oracle在2014年3月份釋出了java8正式版,該版本增加了很多新特性,比如:函式式介面、lambda表示式、集合的流式操作、註解的更新、安全性增強、IO\NIO的改進
函式式介面
什麼是函式式介面
這是java8的一個核心概念,(Functional Interfaces).通過在介面中新增一個抽象方法,這些方法可以直接從介面中執行。我們有兩種方法去實現一個函式式介面
1. 在一個介面中定義唯一一個抽象方法,那麼這個介面就成為函式式介面
2. 通過註解@functionalInterface,用來標註這個介面是一個函式式介面。推薦這種寫法,好處是如果介面不符合函式式介面的定義時,編譯器會報錯
Java.lang.Runnable就是一個典型的函式式介面;
函式式介面的用途
主要用在Lambda表示式和方法引用上
程式碼演示
@FunctionalInterface
public interface IHelloInterface {
void sayHello(String content);
}
public class HelloTest {
public static void main(String[] args) {
IHelloInterface hi = message -> System.out.println(message);
hi.sayHello("how do you do?");
}
}
//輸出: how do you do?
函式式介面的特性
- 函式式介面允許定義靜態方法
- 函式式介面允許定義default方法
- 函式式介面裡允許定義java.lang.Object裡的public方法
@FunctionalInterface
public interface IHelloInterface {
void sayHello(String content);
//default
default void doSomething(){
System.out.println("play football");
}
//extent
@Override
boolean equals(Object object);
//static
static void doOther(){
System.out.println("eating~");
}
}
泛型及繼承關係
介面可以繼承介面,如果一個父介面是一個函式介面,那麼子介面也有可能是一個函式式介面,那麼它的判斷依據是什麼呢?
對於介面I, 假定M是介面成員裡的所有抽象方法的繼承(包括繼承於父介面的方法), 除去具有和Object的public的例項方法簽名的方法, 那麼我們可以依據下面的條件判斷一個介面是否是函式式介面, 這樣可以更精確的定義函式式介面。
如果存在一個一個方法m, 滿足:
• m的簽名(subsignature)是M中每一個方法簽名的子簽名(signature)
• m的返回值型別是M中的每一個方法的返回值型別的替代型別(return-type-substitutable)
那麼I就是一個函式式介面。
情況一
介面Z繼承了X,Y介面的m方法,由於這兩個方法的簽名相同,返回值也一樣,所以Z有唯一的一個抽象方法int m(List arg);,可以作為函式式介面。
方法簽名Y.m既滿足簽名是X.m,並且返回值也滿足,所以Z仍然是函式式介面
編譯出錯,因為沒有一個方法的簽名是所有方法的子簽名
Java.util.function
Lambda表示式在執行期間表示為一個介面函式,而介面函式只是一種只定義了一個抽象方法的介面。儘管java8裡面已經有一些介面符合函式式介面的定義,比如Runnable , Comparator。但是對於我們來說顯然是不夠的。而如果我們需要在程式裡使用非函式數介面來實現lambda表示式的操作,那麼怎麼去做? Java8引入了一個新增的包java.util.function, 專門用來解決這個問題。這個包裡提供了很多介面
Lambda表示式
函式式介面的重要屬性是:我們能夠使用Lambda來例項化他們,Lambda表示式讓你能夠將函式作廢方法引數,或者將程式碼作為資料對待。
優點
在java8出現之前,匿名內部類,監聽器和事件處理的使用都顯得很冗長,程式碼可讀性差,而Lambda表示式的應用能夠是程式碼變得更加緊湊,可讀性增強
語法
Lambda表示式由三個部分組成:
第一部分:一個括號內用逗號分割形式引數,引數是函式式介面裡面方法的引數
第二部分:一個箭頭號 ->
第三部分:方法體,可以是表示式和程式碼塊
情況一
方法體為表示式,則該表示式的值作為返回值返回:
情況二
方法體為程式碼塊,必須要用{}包裹起來,如果該介面有返回值,則需要return返回值,反之則不需要
程式碼演示
情況1, 對內部類進行簡化
//lambda表示式用得最多的場合就是替代匿名內部類,而實現Runnable介面是匿名內部類的經典例子。
private static void test1() {
new Thread(new Runnable() {
@Override
public void run() {
System.out.println("The old runable now is using!");
}
}).start();
new Thread(() -> System.out.println("It is a lambda function")).start();
}
情況2,我們用list排序來演示效果
List<String> word = Arrays.asList("a", "b", "c");
//before
word.sort(new Comparator<String>() {
@Override
public int compare(String o1, String o2) {
return o2.compareTo(o1);
}
});
//after
word.sort((o1, o2)->o2.compareTo(o1));
方法引用
有時候Lambda表示式的程式碼只是一個簡單的方法呼叫而已,而遇到另外一種情況我們可以更進一步去簡化,我們稱之為方法引用;
引用靜態方法
引用物件的例項方法
引用某個型別的任意物件的例項方法
引用類建構函式
程式碼演示
我們同樣針對一個陣列進行排序,綜合以上所有提到的方法引用型別
//first
public class Person implements Comparable<Person> {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int compare(Person p1, Person p2) {
return p1.getName().compareTo(p2.getName());
}
@Override
public int compareTo(Person person) {
return person.getName().compareTo(this.getName());
}
}
//second
public class PersonFactory {
private Supplier<Person> supplier;
public PersonFactory(Supplier<Person> supplier) {
this.supplier = supplier;
}
public Person getPerson() {
return supplier.get();
}
}
//third
public class SupplierTest {
public static void main(String[] args) {
//方法引用:引用類構造
PersonFactory factory = new PersonFactory(Person::new);
List<Person> personList = new ArrayList<>();
Person p1 = factory.getPerson();
p1.setName("alan");
personList.add(p1);
Person p2 = factory.getPerson();
p2.setName("blue");
personList.add(p2);
Person p3 = factory.getPerson();
p3.setName("crow");
personList.add(p3);
System.out.println("before sort");
print(personList);
//靜態方法引用
personList.sort(SupplierTest::myCompare);
System.out.println("after sort");
print(personList);
//##########################################
//方法引用::用特定物件的例項方法
personList.sort(p1::compare);
print(personList);
//引用特定型別的任意物件的例項方法
personList.sort(Person::compareTo);
print(personList);
}
private static void print(List<Person> personList) {
personList.forEach((Person p)->{
System.out.print(p.getName()+" ");
});
System.out.println();
}
private static int myCompare(Person p1, Person p2) {
return p2.getName().compareTo(p1.getName());
}
}
集合流式操作
Java8引入了流式操作(Stream),通過該操作可以實現對集合的並行處理和函式式操作。
1. 根據操作返回的結果不同,流式操作又分為中間操作和最終操作。最終操作返回的是一個特定型別的結果;而中間操作返回的是流本身,因此就可以將多個操作一次串聯起來;
2. 根據流的併發性、又可以分為序列和並行兩種,流式操作實現了對集合的過濾、排序、對映等功能
序列流和並行流
通過序列流操作是在一個執行緒中依次完成,而並行流則是在多個執行緒上同時執行。並行和序列的流操作可以相互切換:通過
Stream.sequential()返回序列流
Stream.parallel() 返回並行流
相比於序列流,並行流可以很大程度上提高程式的執行效率
序列/並行排序演示
private static void test8() {
List<String> list = new ArrayList<>();
for(int i=0;i<1000000;i++) {
double d = Math.random() * 1000;
list.add(d+"");
}
long start = System.nanoTime();
int count = (int) list.stream().parallel().sorted().count();
long end = System.nanoTime();
long ms = TimeUnit.NANOSECONDS.toMillis(end - start);
System.out.println("ms:"+ms);
}
private static void test7() {
List<String> list = new ArrayList<>();
for(int i=0;i<1000000;i++) {
double d = Math.random() * 1000;
list.add(d+"");
}
long start = System.nanoTime();
int count = (int) list.stream().sequential().sorted().count();
long end = System.nanoTime();
long ms = TimeUnit.NANOSECONDS.toMillis(end - start);
System.out.println("ms:"+ms);
}
中間操作
該操作會保持 stream 處於中間狀態,允許做進一步的操作。它返回的還是的 Stream,允許更多的鏈式操作。常見的中間操作有:
filter():對元素進行過濾;
sorted():對元素排序;
map():元素的對映;
distinct():去除重複元素;
subStream():獲取子 Stream 等。
終止操作
該操作必須是流的最後一個操作,一旦被呼叫,Stream 就到了一個終止狀態,該操作之後不能再鏈式的新增其他操作。常見的終止操作有:
forEach():對每個元素做處理;
toArray():把元素匯出到陣列;
findFirst():返回第一個匹配的元素;
anyMatch():是否有匹配的元素等。
相關文章
- JAVA8新特性Java
- Java8 新特性Java
- Java8新特性 - LambdaJava
- Java8的新特性Java
- JAVA8新特性用法Java
- java8新特性stream流Java
- Java8 新特性詳解Java
- Java8新特性系列-LambdaJava
- Java8新特性之:OptionalJava
- Java8新特性--Stream APIJavaAPI
- PHP8 新特性實踐PHP
- Java 8 新特性——實踐篇Java
- ?Java8新特性之Optional類Java
- java8 新特性之方法引用Java
- java8 新特性之Optional 類Java
- Java8新特性(一)-Lambda表示式Java
- Java8新特性探索之Stream介面Java
- Java8新特性(1):Lambda表示式Java
- Java8常用的新特性總結Java
- Java8新特性都到碗裡來Java
- Java8新特性之時間APIJavaAPI
- java8 新特性之Lambda 表示式Java
- java8 新特性之預設方法Java
- Java8新特性之日期-時間APIJavaAPI
- 【java8新特性】蘭姆達表示式Java
- Java8 新特性 —— Stream 流式程式設計Java程式設計
- Java8的新特性--函式式介面Java函式
- java8 新特性之函式式介面Java函式
- java8 新特性之日期時間 APIJavaAPI
- 【Java8新特性】冰河帶你看盡Java8新特性,你想要的都在這兒了!!(文字有福利)Java
- Java8 和 Java9 的主要新特性Java
- 乾貨 | Java8 新特性指導手冊Java
- Java8 新特性 Stream流操作List集合 (二)Java
- Java8新特性探索之函式式介面Java函式
- 汪大神Java8新特性及實戰視訊教程完整版Java
- QQ音樂:React v16 新特性實踐React
- Java8新特性,你應該瞭解這些!Java
- Java8 新特性 —— 函數語言程式設計Java函數程式設計