• 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

    ------------------你若盛开 - 蝴蝶自来------------------
    如果,您认为阅读这篇博客让您有些收获, 如果,您希望更容易地发现我的新博客,不妨关注一下。因为,我的写作热情也离不开您的肯定支持。
    感谢您的阅读,如果您对我的博客所讲述的内容有兴趣,请继续关注我的后续博客。
    因为有小孩,兼职卖书,路过的朋友有需要低价购买图书、点读笔、纸尿裤等资源的,可扫最上方二维码,质量有保证,价格很美丽,欢迎咨询! 欢迎关注微信公众号:18般武艺
  • 相关阅读:
    ping
    android Handler总结
    配置网络测试环境的批处理
    shell 的选项解析
    [转] Linux 中共享库的搜索
    SecureCRT 脚本一则(0720.Rev.1)
    使用 Wget 完成自动 Web 认证(推 portal)
    shell 选项解析之需求一:多路径自动补全
    getopts 的简单模拟(09.12 Rev)
    ThinkPHP框架使用心得三 RBAC权限控制(2)简要原理
  • 原文地址:https://www.cnblogs.com/xifenglou/p/4414694.html
Copyright © 2020-2023  润新知