在Java 8以前只能進行值傳遞,方法是不能傳遞的。若是你想調用一個方法你必須先獲取到它所在的類的實例,而後再經過實例去調用這個方法,可是Java 8新增了方法引用這個新特性可讓你直接把方法當作值來傳遞。segmentfault
1.下面這段代碼代碼的做用是遍歷獲取目錄下全部的文件和目錄,而且還加了一個篩選條件,只篩選出不隱藏的文件和目錄,這裏咱們其實只是想調用FileFilte中的accept方法來進行篩選,可是咱們須要先建立FileFilter的匿名對象,而後重寫整個accept方法,這樣咱們才調用到了這個方法,其中只有第三行代碼是會有變化的,其餘的代碼都是固定的,可是咱們每次仍是要把其餘固定的模板代碼從新寫一遍。數組
File[] hiddenFiles = new File("F:\\test").listFiles(new FileFilter() { public boolean accept(File file) { return !file.isHidden(); } });
2.如今Java 8中的方法引用就解決了這個問題,讓咱們看下列的代碼,咱們發現匿名類和重寫方法的步驟都已經沒有了,上述代碼的本質其實就是調用傳進來的File對象的isHidden方法,如今File:: isHiden
這個寫法就是和上面的代碼是一樣的做用,可是代碼精簡了不少,那些無用的冗餘代碼都不見了。ide
File[] hiddenFiles = new File("F:\\test").listFiles(File::isHidden);
3.咱們從源碼來看看listFiles
方法作了什麼操做,而這兩種寫法又有什麼不一樣。函數
首先listFiles方法接受了一個FileFilter類型的對象,list
方法是獲取全部的文件,files是用來存儲篩選以後的元素,循環全部得到到的文件數組,而後調用FileFilter中的accept方法來進行條件篩選,放入files後返回。this
public File[] listFiles(FileFilter filter) { String ss[] = list(); if (ss == null) return null; ArrayList<File> files = new ArrayList<>(); for (String s : ss) { File f = new File(s, this); if ((filter == null) || filter.accept(f)) files.add(f); } return files.toArray(new File[files.size()]); }
再看看FileFilter對象是什麼,發現它是一個接口,因此Java 8以前的寫法都是寫了個匿名對象來實現這個接口,重寫它的accept方法。看到這裏其實很明顯了,這就是一個策略模式的應用。而方法引用就是讓咱們直接把須要在accept
方法裏調用的方法傳遞進去,不須要像之前同樣來個全家桶寫一堆固定模板。es5
@FunctionalInterface public interface FileFilter { boolean accept(File pathname); }
4.下面的圖介紹了Java 8以前和以後這段代碼的邏輯流程,在Java 8以前是須要先建立FileFilter匿名對象而後再調用File.listFiles
方法,而如今只須要File::isHiden
寫法就能夠達到一樣的目的,其實它的含義就是建立了一個方法引用,因此你能夠經過傳遞引用來傳遞這個方法,就好像你new了一個對象的引用,而後你把這個引用傳遞到別的地方,你就能夠調用這個對象裏的屬性和方法是同樣的道理。spa
上面的方法引用讓咱們能夠把方法也當作值來進行傳遞,可是有時候咱們傳遞進去的代碼並無像File.isHidden
方法同樣封裝起來,而這種狀況也是常常發生的,有時候爲了一個特殊需求我須要寫段代碼來解決,可是次數用的極少,不必封裝個方法,而Lambda表達式則解決了這個問題。code
1.好比咱們想要篩選出一個文件名叫abc.txt的文件,咱們能夠這樣寫,咱們看到 file.getName(). equals("abc.txt"));
是咱們本身寫出來的,咱們並無把它封裝成方法就拿來使用了,注意看->
符號前面,那個表明的是上面accept
方法接受的參數,而->
後面則是咱們拿傳遞進來的參數來操做,只是要確保你的這行代碼返回的類型是要和accept
方法的返回類型一致。對象
File[] files3 = new File("F:\\test").listFiles((File file) -> file.getName().equals("abc.txt"));
2.以上只是Lambda表達式最簡單的方式,咱們還能夠有下列這些更加多樣化的操做,Lambda表達式在Java 8中是很是重要的部分,由於後面咱們講到的stream(流)就是基於它來使用的。blog
//單個參數的時候能夠省略括號和類型,直接寫形參 File[] files4= new File("F:\\test").listFiles((file -> file.getName().equals("abc.txt"))); //若是要寫多行代碼,能夠加大括號把全部代碼括起來,最後你一樣須要返回正確的類型 File[] files5= new File("F:\\test").listFiles( (File file) -> { boolean flag = file.getName().equals("d") && file.getName().contains("d"); return flag; } );
下面我會增長一篇文章關於Lambda表達式的實際應用,好讓你們更好的理解它們的用法。