Java 8之方法引用和Lambda表达式

方法引用:

在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

clipboard.png


Lambda-匿名函数:

上面的方法引用让咱们能够把方法也当作值来进行传递,可是有时候咱们传递进去的代码并无像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表达式的实际应用,好让你们更好的理解它们的用法。

相关文章
相关标签/搜索