Java 8 Lambda表达式探险

为什么?
   我们为什么需要Lambda表达式
   主要有三个原因:
   > 更加紧凑的代码
     比如Java中现有的匿名内部类以及监听器(listeners)和事件处理器(handlers)都显得很冗长
   > 修改方法的能力(我个人理解为代码注入,或者有点类似JavaScript中传一个回调函数给另外一个函数)
     比如Collection接口的contains方法,当且仅当传入的元素真正包含在集合中,才返回true。而假如我们想对一个字符串集合,传入一个字符串,只要这个字符串出现在集合中(忽略大小写)就返回true。
     简单地说,我们想要的是传入“一些我们自己的代码”到已有的方法中,已有的方法将会执行我们传入的代码。Lambda表达式能很好地支持这点
   > 更好地支持多核处理
     例如,通过Java 8新增的Lambda表达式,我们可以很方便地并行操作大集合,充分发挥多核CPU的潜能。
     并行处理函数如filter、map和reduce。

怎么做?
   实例1 FileFilter

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

通过Lambda表达式这段代码可以简化为如下:

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<String> list = new ArrayList<String>();
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<String> list = getMyStrings();
for(String myString: list) {
   if(myString.contains(possible)) {
       System.out.println(myString + " contains " + possible);
   }
}

使用Predicate和Filter后得到下面代码:

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

进一步简化:

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

Lambda表达式语法规则
   到目前为止Java 8中的Lambda表达式语法规则还没有完全确定。
   但这里简单介绍下:
   对于前面的:

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

accept()方法返回布尔值,这种情况f.isDirectory()显然也得是布尔值。这很简单。
   而对于:

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

actionPerformed()方法的返回类型是void,所以需要特殊处理,即在ui.showSomething();左右加上花括号。(想象下不加会怎么样?如果不加的话,若showSomething()方法返回值是整数类型,那么就意味着actionPerformed()返回整数类型,显然不是,所以必须加花括号用来标记)。
   如果Lambda表达式主体部分包含多条语句,也必须用花括号,并且return语句不能省。
   比如下面这个:

File dir = new File("/an/dir/");
File[] dirs = dir.listFiles((File f) ->  {
                                            System.out.println("Log:...");
                                            return f.isDirectory();
                                         }
);

参考自:http://www.oraclejavamagazine-digital.com/javamagazine/20121112?sub_id=hlBuL1SAFxXX#pg35

时间: 2024-10-10 21:07:01

Java 8 Lambda表达式探险的相关文章

Java 8 lambda表达式示例

例1.用lambda表达式实现Runnable 我开始使用Java 8时,首先做的就是使用lambda表达式替换匿名类,而实现Runnable接口是匿名类的最好示例.看一下Java 8之前的runnable实现方法,需要4行代码,而使用lambda表达式只需要一行代码.我们在这里做了什么呢?那就是用() -> {}代码块替代了整个匿名类. 1 // Java 8之前: 2 new Thread(new Runnable() { 3 @Override 4 public void run() {

用Java 8 Lambda表达式实现设计模式:命令模式

链接:http://www.importnew.com/16789.html 在这篇博客里,我将说明如何在使用Java 8 Lambda表达式的函数式编程方式时实现命令设计模式.命令模式的目标是将请求封装成一个对象,从对客户端的不同类型请求,例如队列或日志请求参数化,并提供相应的操作.命令模式是一种通用编程方式,该方式基于运行时决策顺序来执行方法.模式的参与者如下: 命令 :声明用于执行操作的接口. 实体命令 :定义接收者对象和动作的绑定. 客户端 :创建实体命令实例并设置它的接收者. 调用者:

Java 8 Lambda表达式10个示例【存】

PS:不能完全参考文章的代码,请参考这个文件http://files.cnblogs.com/files/AIThink/Test01.zip 在Java 8之前,如果想将行为传入函数,仅有的选择就是匿名类,需要6行代码.而定义行为最重要的那行代码,却混在中间不够突出.Lambda表达式取代了匿名类,取消了模板,允许用函数式风格编写代码.这样有时可读性更好,表达更清晰.在Java生态系统中,函数式表达与对面向对象的全面支持是个激动人心的进步.将进一步促进并行第三方库的发展,充分利用多核CPU.尽

Java之Lambda表达式和Stream类简单例子

开心一笑 提出问题 java的lambda表达式和Stream如何使用??? 解决问题 Lambda表达式的语法 基本语法: (parameters) -> expression 或 (parameters) ->{ statements; } 看例子学习吧! 例一:定义一个AyPerson类,为之后的测试做准备. package com.evada.de; import java.util.Arrays; import java.util.List; class AyPerson{ priv

Java 8 lambda表达式20180404

Java 8 lambda表达式示例 我个人对Java 8发布非常激动,尤其是lambda表达式和流API.越来越多的了解它们,我能写出更干净的代码.虽然一开始并不是这样.第一次看到用lambda表达式写出来的Java代码时,我对这种神秘的语法感到非常失望,认为它们把Java搞得不可读,但我错了.花了一天时间做了一些lambda表达式和流API示例的练习后,我开心的看到了更清晰的Java代码.这有点像学习泛型,第一次见的时候我很讨厌它.我甚至继续使用老版Java 1.4来处理集合,直到有一天,朋

Java的Lambda表达式

Java的Lambda表达式 1. 什么是Lambda表达式 简单的说,Lambda表达式就是匿名方法.Lambda表达式让程序员能够使用更加简洁的代码,但是同样也使代码的可读性比较差. Lambda表达式也叫做匿名方法或者闭包. 2. 和匿名内部类做对比 Lambda是匿名方法,这个时候我们会想想到匿名内部类,我们来回想一下匿名内部类的用法,比如下面的代码就是使用匿名内部类实现了一个线程. public class Test { public static void main(String[]

Java 8 Lambda表达式

Java 8中Lambda表达式就是一个函数接口,也就是只有一个抽象方法的接口. Java中,传递一个行为是通过传递一个代表某种行为的对象来实现,比如,需要给某个按钮注册一个事件监听: button.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { System.out.println("button clicked"); } }); 通过匿名内

[Java 8] Lambda表达式对递归的优化 - 使用尾递归

递归优化 很多算法都依赖于递归,典型的比如分治法(Divide-and-Conquer).但是普通的递归算法在处理规模较大的问题时,常常会出现StackOverflowError.处理这个问题,我们可以使用一种叫做尾调用(Tail-Call Optimization)的技术来对递归进行优化.同时,还可以通过暂存子问题的结果来避免对子问题的重复求解,这个优化方法叫做备忘录(Memoization). 本文首先对尾递归进行介绍,下一票文章中会对备忘录模式进行介绍. 使用尾调用优化 当递归算法应用于大

Java SE 8 for the Really Impatient读书笔记——Java 8 Lambda表达式

1. lambda表达式的语法 语法十分简单:参数->主体 1.1 参数 可以是零个参数,一个参数,也可以是多个参数,参数可以指定类型,在编译器可以推导出参数类型的情况下,也可以省略参数类型. 两个参数的例子: (String first, String second)-> Integer.compare(first.length(), second.length()) 0个参数的例子: () -> { for (int i = 0; i < 1000; i++) doWork()