zoukankan      html  css  js  c++  java
  • lambda 表达式学习笔记

      在Java中传递一个代码段并不容易,不能直接传递代码段。Java是一个面向对象语言,所以必须构造一个对象,这个对象的类需要一个方法能包含所需的代码。lambda的出现有效的解决这个问题,让代码变得更加简洁。

    示例:

    class LengthComparator implements Comparator<String>{
        public int compare(String first,String second){
             return first.length() - second.length();     
        }
    }    
    ...
    Arrays.sort(Strings,new LengthComparator());
    Arrays.sort(strings,
      (String first,String second)
    -> first.length() - second.length());

      lambda表达式,也可称为闭包,是一个可传递的代码块,可以执行一次或多次。

    一、lambda表达式的语法:

      lambda表达式的语法:参数,箭头(->)以及一个表达式。

    (String first,String second)

       -> first.length() - second.length();

      如无法放在一个表达式中,可放在{}中:

    (String first,String second)->
     {
      if(first.length() < second.length()) return -1;
      else if(first.length() > second.length()) return 1;
      else return 0;
     }

       即使lambda表达式没有参数,仍然要提供空括号,就像无参数方法一样:

    ()-> {for(int i = 100; i >= 0 ; i--)  System.out.println(i) ; }

      如果方法只有一个参数,而且这个参数的类型可以推导得出,那么甚至可以省略小括号:

    ActionListener listener = event ->

    System.out.println("The times is" + new Date());

      //Instead of (event) -> ... or (ActionEvent event) -> ...

      无需指定lambda表达式的返回值类型,lambda表达式的返回值类型总是会由上下文推导得出,例如:

    (String first,String second)-> first.length() - second.length();

      可以在需要int类型结果的上下文中使用。

      示例:

     1 package lambda;
     2 
     3 import javax.swing.*;
     4 import java.util.Arrays;
     5 import java.util.Date;
     6 
     7 /**
     8  * Created by kong on 20/11/2017.
     9  */
    10  
    11 public class LambdaTest {
    12     public static void main(String[] args) {
    13         String[] planets = new String[]{"Mercury","Venus","Mars",
    14             "Jupiter","Saturn","Uranus","Neptune"};
    15         System.out.println (Arrays.toString (planets));
    16         System.out.println ("Sorted in dictionary order:");
    17         Arrays.sort (planets);
    18         System.out.println (Arrays.toString (planets));
    19         System.out.println ("Sorted by length:");
    20         Arrays.sort (planets,(first,second) -> first.length () - second.length ());
    21         System.out.println (Arrays.toString (planets));
    22 
    23         Timer t  = new Timer (1000, event ->
    24                 System.out.println ("The time is "+ new Date ()));
    25         t.start();
    26         JOptionPane.showMessageDialog (null,"Quit program?");
    27         System.exit (0);
    28     }
    29 }

    //运行结果

    [Mercury, Venus, Mars, Jupiter, Saturn, Uranus, Neptune]
    Sorted in dictionary order:
    [Jupiter, Mars, Mercury, Neptune, Saturn, Uranus, Venus]
    Sorted by length:
    [Mars, Venus, Saturn, Uranus, Jupiter, Mercury, Neptune]
    The time is Mon Nov 20 19:58:41 CST 2017
    The time is Mon Nov 20 19:58:42 CST 2017

      二、函数式接口

       对于只有一个抽象方法的接口,需要这种接口的对象时,就可以提供一个lambda表达式。这种接口称为函数式接口(functional interface)。

      三、方法的引用

        要用 :: 操作符分隔方法名与对象或类名。主要有三种情况:

      • object::instanceMethod
      • Class::staticMethod
      • Class::instanceMethod

        在前两种情况中,方法引用等价于提供方法参数的lambda表达式。如:

        System.out::println 等价于 x -> System.out.println(x);

        Math::pow 等价于(x,y) -> Math.pow(x,y)。

        对于第三种情况下,第一个参数会成为方法的目标,如:

        String::compareToIgnoreCase 等同于(x,y) -> x.compareToIgnoreCase(y)。

        示例:

     1 import java.util.List;
     2 import java.util.ArrayList;
     3  
     4 public class Java8Tester {
     5    public static void main(String args[]){
     6       List names = new ArrayList();
     7         
     8       names.add("Google");
     9       names.add("Runoob");
    10       names.add("Taobao");
    11       names.add("Baidu");
    12       names.add("Sina");
    13         
    14       names.forEach(System.out::println);
    15    }
    16 }

      四、构造器引用

      构造器引用与方法引用类似,只不过方法名为new。如:

      ArrayList<String> names = ...;

      Stream<Person> stream = names.stream().map(Person::new);

      List<Person> people = stream.collect(Collectors.toList());

      map方法会为各个列表元素调用Person(String)构造器,如果有多个构造器,编译器会选择有一个String参数的构造器,因为上下文推导出这是在对一个字符串调用构造器。

      又如:int[]::new 是一个构造器引用,它有一个参数,即数组的长度。这等价于lambda表达式 x -> new int[x] 。

      五、变量作用域

      在lambda表达式中捕获的变量必须实际上是最终变量(即这个变量初始之后就不会再为它赋新值);

      下面做法是不合法的:

    1 public static void countDowm(int start,int delay){
    2       ActionListener listener = event -> {
    3            start--;//Error:Can't mutate captured variable
    4            System.out.println(start);          
    5            };  
    6        new Timer(delay,listener).start();
    7 }

      在lambda表达式中声明与一个局部变量同名的参数或局部变量是不合法的。如:

    1 Path first = Paths.get("/urs/bin");
    2 Comparator<String> comp = 
    3     (first,second) -> first.length() - second.length();
    4      //Error:Variable first already defined

      六、处理lambda表达式

      使用lambda表达式的重点是延迟执行(deferred execution)。原因如:

      • 在一个单独的线程中运行代码;
      • 多次运行代码;
      • 在算法的适当位置运行代码(如,排序中的比较操作);
      • 发生某种情况下执行代码(如,点击了一个按钮,数据到达,等待);
      • 只在必要时运行代码;

      如重复一个动作n次:

      repeat(10,()-> System.out.println("Hello World!")); 

  • 相关阅读:
    (二)juc线程高级特性——CountDownLatch / Callable / Lock
    (一)juc线程高级特性——volatile / CAS算法 / ConcurrentHashMap
    配置tomcat的session共享
    elastic不错的官方文档(中文)
    elasticsearch java客户端api使用(一)
    Tomcat 没有自动解压webapp下的war项目文件问题
    Spring+Quartz实现定时任务
    注意的问题
    JMS之——ActiveMQ 高可用与负载均衡集群安装、配置(ZooKeeper + LevelDB + Static discovery)
    activemq持久化配置,设置为主从模式(带复制的主从模式,应用mysql数据库)
  • 原文地址:https://www.cnblogs.com/gdwkong/p/7868011.html
Copyright © 2011-2022 走看看