Java与JVM中的Lambda表达式

欢迎进入Java社区论坛,与200万技术人员互动交流 >>进入

  除了新的Lambda表达式语法以外,Lambda项目还包括一个经过大幅升级的集合框架类库。这次升级的目的是为了能更易于编写使用内部遍历的代码,以支持一系列众所周知的函数式编程典范。

  使用Lambda的函数式编程

  曾经,大多数开发者发现他们需要集合能够执行如下一种或几种操作:

  1. 创建一个新的集合对象,但要过滤掉不符合条件的元素。

  2. 对集合中的元素逐一进行转化,并使用转化后的集合。

  3. 创建集合中所有元素的某个属性的总体值,例如,合计值与平均值。这样的任务(分别称之为过滤,映射和化简)具有共通的要点:它们都需要处理集合中的每个元素。

  程序无论是判定某个元素是否存在,或是判断元素是否符合某个条件(过滤),或是将元素转化成新元素并生成新集合(映射),或是计算总体值(化简),关键原理就是”程序必须处理到集合中的每个元素”.

  这就暗示我们需要一种简单的途径去表示用于内部遍历的程序。幸运地是,Java SE 8为此类表示法提供了构建语句块。

  支持基本函数式编程的Java SE 8类

  Java SE 8中的一些类意在被用于实现前述的函数式典范,这些类包括Predicate,Mapper和Block–当然,还有其它的一些类–它们都在一个新的java.util.functions包中。

  看看Predicate类的更多细节,该类常被用于实现过滤算法;将它作用于一个集合,以返回一个包含有符合谓语条件元素的新集合。何为谓语,有很多种解释。Java SE 8认为谓语是一个依据其变量的值来判定真或假的方法。

  再考虑一下我们之前看过的一个例子。给定一个字符串的集合,我们想判定它是否包含有指定的字符串,但希望字符串的比较是大小写不敏感的。

  在Java SE 7中,我们将需要使用外部遍历,其代码将如清单8所示,

  清单8

  public void printMatchedStrings(List<String> myStrings) {

  List<String> out = new ArrayList<>();

  for (String s: myStrings) {

  if (s.equalsIgnoreCase(possible))

  out.add(s);

  }

  log(out);

  }

  而在即将发布的Java SE 8中,我们使用Predicate以及Collections类中一个新的助手方法(过滤器)就可写出更为紧凑的程序,如清单9所示,

  清单9

  public void printMatchedStrings() {

  Predicate<String> matched = s -> s.equalsIgnoreCase(possible);

  log(myStrings.filter(matched));

  }

  事实上,如果使用更为通用的函数式编程风格,你只需要写一行代码,如清单10所示,

  清单10

  public void printMatchedStrings() {

  log(myStrings.filter(s -> s.equalsIgnoreCase(possible)));

  }

  如你所见,代码依然非常的易读,并且我们也体会到了使用内部遍历的好处。

  最后,让我们讨论一下Lambda表达式语法的更多细节。

  Lambda表达式的语法规则

  Lambda表达式的基本格式是以一个可被接受的参数列表开头,以一些代码(称之为表达式体/body)结尾,并以箭头(->)将前两者分隔开。

  注意:Lambda表达式的语法仍可能会面临改变,但在撰写本文的时候,下面示例中所展示的语法是能够正常工作的。

  Lambda表达式非常倚重类型推导,与Java的其它语法相比,这显得极其不同寻常。

  让我们进一步考虑之前已经看过的一个示例(请见清单11)。如果看看ActionListener的定义,可以发现它只有一个方法(请见清单12)。

  清单11

  ActionListener listener = event -> {ui.showSomething();};

  清单12

  public interface ActionListener {

  public void actionPerformed(ActionEvent event);

  }

  所以,在清单11右侧的Lambda表达式,能够很容易地理解为”这是针对仅声明单个方法的接口的方法定义”.注意,仍然必须要遵守Java静态类型的一般规则;这是使类型推导能正确工作的唯一途径。

  据此可以发现,使用Lambda表达式可以将先前所写的匿名内部类代码转换更紧凑的代码。

  还需要意识到有另一个怪异的语法。让我们再回顾下上述示例,如清单13所示,

  清单13

  FileFilter directoryFilter = (File f) -> f.isDirectory();

  仅一瞥之,它看起来与ActionListener的示例相似,但让我们看看FileFilter接口的定义(请见清单14)。accept()方法会返回一个布尔值,但并没有一个显式的返回语句。相反,该返回值的类型是从Lambda表达式中推导出来的

  清单14

  public interface FileFilter {

  public boolean accept(File pathname);

  }

  这就能解释,当方法返回类型为void时,为什么要进行特别处理了。对于这种情形,Lambda表达式会使用一对额外的小括号去包住代码部分(表达式体/body)。若没有这种怪异的语法,类型推导将无法正常工作–但你要明白,这一语法可能会被改变。

  Lambda表达式的表达式体可以包含多条语句,对于这种情形,表达式体需要被小括号包围住,但”被推导出的返回类型”这种语法将不启作用,那么返回类型关键字就必不可少。

  最后还需要提醒你的是:当前,IDE似乎还不支持Lambda语法,所以当你第一次尝试Lambda表达式时,必须要格外注意javac编译器抛出的任何警告。

  结论

  Lambda表达式是自Java SE 5引入泛型以来最重大的Java语言新特性。应用得当,Lambda表达式可使你写出简洁的代码,为已有方法增加额外的功能,并能更好地适应多核处理器。到目前为止,我们能肯定的是,你正急切地想去尝试Lambda表达式,所以咱也别?嗦了…

[1][2]

趁着有脾气装潇洒,有本钱耍个性,

Java与JVM中的Lambda表达式

相关文章:

你感兴趣的文章:

标签云: