Java8 Lambda【簡】

Java8 Lambda

Lambda是一個表達式,也能夠說它是一個匿名函數。然而在使用它或是閱讀Lambda代碼的時候,卻顯得並不那麼容易。由於它匿名,由於它刪減了一些必要的說明信息(好比方法名)。java

 

1、爲何要用Lambda表達式

1.更加緊湊的代碼

好比Java中現有的匿名內部類以及監聽器(listeners)和事件處理器(handlers)都顯得很冗長linux

2.修改方法的能力

(我我的理解爲代碼注入,或者有點相似JavaScript中傳一個回調函數給另一個函數)  好比Collection接口的contains方法,當且僅當傳入的元素真正包含在集合中,才返回true。而假如咱們想對一個字符串集合,傳入一個字符串,只要這個字符串出如今集合中(忽略大小寫)就返回true。編程

3.更好地支持多核處理

 例如,經過Java 8新增的Lambda表達式,咱們能夠很方便地並行操做大集合,充分發揮多核CPU的潛能。並行處理函數如filter、map和reduce。數組

 

 

2、變量做用域說明

關於變量在Lambda中的做用域,主要表如今如下幾點:併發

  • 對局部變量可見
  • 對全局變量可見
  • 對當前層傳入的參數可見
  • 對上層函數傳入的參數可見
  • 對上層Lambda傳入的參數可見

3、實例

   實例1 FileFilter

File dir = new File("/an/dir/");   
FileFilter directoryFilter = new FileFilter() {      
	public boolean accept(File file) {         
		return file.isDirectory();      
	}
};

   經過Lambda表達式這段代碼能夠簡化爲以下:app

File dir = new File("/an/dir/");
FileFilter directoryFilter = (File f) -> f.isDirectory();
File[] dirs = dir.listFiles(directoryFilter);

   進一步簡化:函數式編程

File dir = new File("/an/dir/");
File[] dirs = dir.listFiles((File f) -> f.isDirectory());

Lambda表達式使得代碼可讀性加強了。我認可我開始學習Java的時候對那個匿名內部類感到很困擾,而如今Lambda表達式讓這一切看起來都很天然(尤爲是有.NET背景的童鞋會發現這個跟.NET中的Lambda表達式好像)  函數

 Lambda表達式利用了類型推斷(type inference)技術
編譯器知道FileFilter只有一個方法accept(),因此accept()方法確定對應(File f) -> f.isDirectory(),並且accept()方法只有一個File類型的參數,因此(File f) -> f.isDirectory()中的File f就是這個參數了,.NET把類型推斷作得更絕,若是上面用.NET Lambda表達式寫法的話是這樣的: File[] dirs = dir.ListFiles(f => f.isDirectory());即壓根就不須要出現File類型指示。工具

   實例2 Event Handler

Button bt = new Button(); 
bt.addActionListener(new ActionListener() { 
	public void actionPerformed(ActionEvent e) { 
		ui.showSomething(); 
	}
});

 使用Lambda表達式後:學習

Button bt = new Button();
ActionListener listener = event -> { 
	ui.showSomething(); 
};
bt.addActionListener(listener);

   進一步簡化: 

Button bt = new Button();
bt.addActionListener(event -> { 
	ui.showSomething(); 
});

外循環、內循環和Map、Reduce、Filter

   一直到如今,處理Java集合的標準作法是採用外循環。好比:

List list = new ArrayList();
list.add("hello");
list.add("world");
for(int item: list) { 
	// 處理item
}

   還有迭代器循環,它們都是外循環,而且都是順序處理(sequential handling)。順序特性也經常引起ConcurrentModificationException(併發修改異常),只要咱們嘗試着併發修改集合。

   Lambda表達式提供了內循環機制

   咱們工做中可能常常面臨下面的需求:

  • 過濾掉一個集合中不符合條件的元素獲得一個新集合
  • 對集合中的每一個元素進行某種轉換,而且對轉換後的集合進行處理
  • 統計整個集合的某個屬性,好比統計集合元素值的總和或平均值

這些任務即filter、map和reduce,他們的共同特色是須要對集合中的每一個元素運行一小段相同的代碼

   傳統的實現這些任務的代碼讓人感到很乏味,幸運的是Java 8提供了完成這些任務的更簡潔的方案,固然仍是利用Lambda表達式,但也引入了一個新的類庫java.util.functions,包含Predicate、Mapper和Block。

   Java 8中,一個Predicate(謂詞)是這樣一個方法:它根據變量的值進行評估(evaluate),返回true或false。

   好比下面:

List list = getMyStrings();
for(String myString: list) { 
	if(myString.contains(possible)) { 
		System.out.println(myString + " contains " + possible); 
	}
}

   使用Predicate和Filter後獲得下面代碼:

List list = getMyStrings();
Predicate matched = s -> s.equalsIgnoreCase(possible);
list.filter(matched);

   進一步簡化:

List list = getMyStrings();
list.filter(s -> s.equalsIgnoreCase(possible));

 

 

 

 

4、Lambda評價

優勢

  1. 在普通代碼裏幾行的代碼,在Lambda中只須要一行就能夠解決。因此代碼比之前更簡潔了
  2. 能夠在某一個方法內部定義,這樣能夠提升操做的便捷性

缺點

  1. Lambda是一個匿名函數,由於是匿名,因此可讀性變差了
  2. 有時候有多個Lambda嵌套,讓程序變得難以理解

 

 

 

Java8的十大新特性

1、Lambda表達式

Lambda表達式能夠說是Java 8最大的賣點,她將函數式編程引入了Java。Lambda容許把函數做爲一個方法的參數,或者把代碼當作數據。

一個Lambda表達式能夠由用逗號分隔的參數列表、–>符號與函數體三部分表示。例如:

Arrays.asList( "p", "k", "u","f", "o", "r","k").forEach( e -> System.out.println( e ) );

爲了使現有函數更好的支持Lambda表達式,Java 8引入了函數式接口的概念。函數式接口就是隻有一個方法的普通接口。java.lang.Runnable與java.util.concurrent.Callable是函數式接口最典型的例子。爲此,Java 8增長了一種特殊的註解@FunctionalInterface

@FunctionalInterface
public interface Functional {
    void method();
}

2、接口的默認方法與靜態方法

咱們能夠在接口中定義默認方法,使用default關鍵字,並提供默認的實現。全部實現這個接口的類都會接受默認方法的實現,除非子類提供的本身的實現。例如:

public interface DefaultFunctionInterface {
    default String defaultFunction() {
        return "default function";
    }
}

咱們還能夠在接口中定義靜態方法,使用static關鍵字,也能夠提供實現。例如:

public interface StaticFunctionInterface {
    static String staticFunction() {
        return "static function";
    }
}

接口的默認方法和靜態方法的引入,其實能夠認爲引入了C++中抽象類的理念,之後咱們不用在每一個實現類中都寫重複的代碼了。

3、方法引用

一般與Lambda表達式聯合使用,能夠直接引用已有Java類或對象的方法。通常有四種不一樣的方法引用:

  1. 構造器引用。語法是Class::new,或者更通常的Class< T >::new,要求構造器方法是沒有參數
  2. 靜態方法引用。語法是Class::static_method,要求接受一個Class類型的參數;
  3. 特定類的任意對象方法引用。它的語法是Class::method。要求方法是沒有參數的;
  4. 特定對象的方法引用,它的語法是instance::method。要求方法接受一個參數,與3不一樣的地方在於,3是在列表元素上分別調用方法,而4是在某個對象上調用方法,將列表元素做爲參數傳入;

4、重複註解

在Java 5中使用註解有一個限制,即相同的註解在同一位置只能聲明一次。Java 8引入重複註解,這樣相同的註解在同一地方也能夠聲明屢次。重複註解機制自己須要用@Repeatable註解。Java 8在編譯器層作了優化,相同註解會以集合的方式保存,所以底層的原理並無變化。

5、擴展註解的支持

Java 8擴展了註解的上下文,幾乎能夠爲任何東西添加註解,包括局部變量、泛型類、父類與接口的實現,連方法的異常也能添加註解。

6、Optional

Java 8引入Optional類來防止空指針異常,Optional類最早是由Google的Guava項目引入的。Optional類其實是個容器:它能夠保存類型T的值,或者保存null。使用Optional類咱們就不用顯式進行空指針檢查了。

7、Stream

Stream API是把真正的函數式編程風格引入到Java中。其實簡單來講能夠把Stream理解爲MapReduce,固然Google的MapReduce的靈感也是來自函數式編程。她實際上是一連串支持連續、並行彙集操做的元素。從語法上看,也很像linux的管道、或者鏈式編程,代碼寫起來簡潔明瞭,很是酷帥!

8、Date/Time API (JSR 310)

Java 8新的Date-Time API (JSR 310)受Joda-Time的影響,提供了新的java.time包,能夠用來替代 java.util.Date和java.util.Calendar。通常會用到Clock、LocaleDate、LocalTime、LocaleDateTime、ZonedDateTime、Duration這些類,對於時間日期的改進仍是很是不錯的。

9、JavaScript引擎Nashorn

Nashorn容許在JVM上開發運行JavaScript應用,容許Java與JavaScript相互調用。

10、Base64

在Java 8中,Base64編碼成爲了Java類庫的標準。Base64類同時還提供了對URL、MIME友好的編碼器與解(jie)碼(ma)器。

除了這十大新特性以外,還有另外的一些新特性:

  • 更好的類型推測機制:Java 8在類型推測方面有了很大的提升,這就使代碼更整潔,不須要太多的強制類型轉換了。
  • 編譯器優化:Java 8將方法的參數名加入了字節碼中,這樣在運行時經過反射就能獲取到參數名,只須要在編譯時使用-parameters參數。
  • 並行(parallel)數組:支持對數組進行並行處理,主要是parallelSort()方法,它能夠在多核機器上極大提升數組排序的速度。
  • 併發(Concurrency):在新增Stream機制與Lambda的基礎之上,加入了一些新方法來支持彙集操做。
  • Nashorn引擎jjs:基於Nashorn引擎的命令行工具。它接受一些JavaScript源代碼爲參數,而且執行這些源代碼。
  • 類依賴分析器jdeps:能夠顯示Java類的包級別或類級別的依賴。
  • JVM的PermGen空間被移除:取代它的是Metaspace(JEP 122)。
相關文章
相關標籤/搜索