最近一直找java8相關新特性的文章,發現都太沒有一個連貫性,畢竟大家寫博客肯定都有自己的側重點,這里找到一本書,專門介紹java8新特性的,感覺大家可以看看《寫給大忙人看的JavaSE8》.這里我會結合書中的知識以及網上的知識,對於java8 的新特性進行總結,當然我自己寫的也會有自己的側重點。
java8為什么增加了函數式編程
java作為一門面向對象的編程語言誕生於20世紀90年代。在當時,面向對象編程是軟件開發的主流模式。
由於最近在並發和事件驅動(或者稱為“互動”)編程中的優勢,函數式編程又逐漸變得重要起來。
這並不意味着面向對象編程不好,相反,最終的趨勢是將面向對象編程和函數編程結合起來。
java8主要在原來面向對象的基礎上增加了函數式編程的能力.
函數式編程的語言我就了解過一個_Erlang,有興趣的大家可以看看Erlang這門語言。比如消息中間件rabbitmq 就是采用erlang寫的。只要用過erlang的一定知道堅強2002和阿里的余鋒。還有再推薦一個博客為“沒有開花的樹”的博主。至少對我幫助蠻多的。(有點扯遠了)
為什么要使用lambda表達式
lambda表達式的定義
lambda表達式是一段可以傳遞的代碼,因此它可以被執行一次或者多次。
實戰代碼對比
之前我們要在另一個獨立線程中執行一些邏輯時,通常會將代碼放到一個實現Runnable接口的類的run方法中。如下面
public class Worker implements Runnable {
@Override
public void run() {
for (int i = 0; i < 1000; i++) {
System.out.println("doWork" + i);
}
}
}
執行代碼
public static void main(String[] args) {
Worker worker = new Worker();
new Thread(worker).start();
}
這段代碼的關鍵在於,run方法中包含了你希望在另一個線程中需要執行的代碼。
到現在為止,在java 中向其他代碼傳遞一段代碼並不是很容易的。你不得不構建一個屬於某個類的對象,由它的某個方法來包含所需的代碼。
我們看看使用lambda表達式重寫上面的方法
new Thread(() -> {
for (int i = 0; i < 1000; i++) {
System.out.println("doWork" + i);
}
}).start();
lambda表達式語法
一般語法
(Type1 param1,Type2 params,...) -> {
statment1;
statment2;
.....
return statmentM;
}
單參數語法
可以省略前面的小括號,但是我一般都是帶着
param1 ->{
...
...
return ...;
}
單語句語法
可以省略后面的大括號
param1 -> statment
函數式接口
在java中有許多已有的接口都需要封裝代碼塊,如Runnable。lambda表達式與這些接口都是向后兼容的。
對於只包含一個抽象方法的接口,你可以通過lambda表達式來創建該接口的對象。這種接口被稱為函數式接口。
這里注意一點,大家都知道接口中的方法是抽象的。事實上,接口經常會重新聲明Object類中的方法。如toString等 這些方法命名並不是抽象的。
我們看下Runnable的代碼 源碼
@FunctionalInterface
public interface Runnable {
/**
* When an object implementing interface <code>Runnable</code> is used
* to create a thread, starting the thread causes the object's
* <code>run</code> method to be called in that separately executing
* thread.
* <p>
* The general contract of the method <code>run</code> is that it may
* take any action whatsoever.
*
* @see java.lang.Thread#run()
*/
public abstract void run();
}
注意有個@FunctionalInterface 注解,有2個作用
- 編譯器會檢查標注該注解的實體,檢查它是否是只包含一個抽象方法的接口。
- 在jacadoc頁面也會包含一條聲明,說明這個接口是一個函數式接口。
但是這個注解並不是強制使用,從概念上講,所有只含有一個抽象方法的接口都是函數式接口,但是使用@FunctionalInterface 注解會讓你的代碼更加清楚,畢竟代碼的可讀性是編程的第一規范。
方法引用
有時候,你想要傳遞給其他代碼的操作已經有實現的方法。
Class or instance :: method
比如
(x) -> System.out.println(x);
就等同於
System.out::println;
構造器引用
-
構造器引用同方法引用類似,不同的是在構造器引用中方法名是 new.
-
對於擁有多個構造器的類,選擇使用哪個構造器取決於上下文
Class :: new
變量作用域
外部變量在 lambda 表達式引用時,jdk 8 編譯器會隱式做為 final 來處理