zoukankan      html  css  js  c++  java
  • Java 8 Lambda表达式学习和理解

    Java 8 Lambda表达式和理解

    说明:部分资料来源于网络

    时间:20190704

    Lambda 表达式,也可称为闭包,它是推动 Java 8 发布的最重要新特性。Lambda 允许把函数作为一个方法的参数(函数作为参数传递进方法中)。使用 Lambda 表达式可以使代码变的更加简洁紧凑。

    一、语法

    1、lambda 表达式的语法格式如下:

      (左边)输入参数->(右边)lambda主体

    (parameters) -> expression;

      或

    (parameters) ->{ statements; }

    2、以下是lambda表达式的重要特征:

    (1)输入参数:

      可选类型声明:不需要声明参数类型,编译器可以统一识别参数值。

      可选的参数圆括号:

        a、一个参数无需定义圆括号,但多个参数需要定义圆括号。

        b、如果申明了参数类型,则一定需要圆括号。

    (2)lambda主体

      可选的大括号:如果主体包含了一个语句,就不需要使用大括号。

      可选的返回关键字:如果主体只有一个表达式返回值则编译器会自动返回值,大括号需要指定明表达式返回了一个数值

    3、按照上面的格式,lambda不同参数的表达式写法

    (1)没有参数的表达式:

    () -> System.out.println("this is no parameter Lambda expression");

    (2)只有一个参数的表达式:

    (x) -> System.out.println("this is only one parameter Lambda expression");

      或者

    (X x) -> System.out.println("this is only one parameter Lambda expression");

      和

    (x) -> {
        x = x*2;
        System.out.println("this is only one parameter Lambda expression");
        System.out.println("the function is double input value");
        return x;
    };

      说明:一个参数的可以不用使用(),如果参数声明了参数类型则必须要加()Lambda主体是语句块的话需要使用{}

    (3)有两个或者多个参数的表达式:

    (x,y) -> System.out.println("these are several parameters Lambda expression");

      或者

    (X x,Y y) -> {
      System.out.println("the function is add two input values");
      System.out.println("these are several parameters Lambda expression");
      return x+y;
    };

      说明:有多个参数的lambda表达式,参数使用,隔开。Lambda主体是语句块的话需要使用{}

    二、Lambda 表达式实例

    lambda示例1:

    /*
     * Predicate<T>接口中boolean test(T t)方法只接收一个参数,返回值为boolean类型,
     * 故lambda表达式的输入参数只有一个参数:x,lambda的主体返回值为boolean类型
     */
    Predicate<Integer> atLeast5 = x -> x >= 5;
    System.out.println("传入参数是否大于5:" + atLeast5.test(6));
    
    /*
     * BinaryOperator<T>接口中R apply(T t, U u)方法接收两个泛型参数,返回值为也为泛型
     * 故lambda表达式输入Long参数有两个:x,y,lambda的主体返回值为Long类型
     */
    BinaryOperator<Long> addLongs = (x, y) -> {
      Long z = x + y;
      return z;
    };
    System.out.println("计算传入两个Long参数的和:" + addLongs.apply(5l, 6l));
    
    /*
     * Runnable接口中run()方法没有参数,有没有返回值,故lambda表达式没有参数,lambda主体也没有返回值
     */
    Runnable run1 = () -> System.out.println("这个方法就是run里面的方法");
    run1.run();
    
    try {
      final Integer value = 9;
      /*
       *  1、Callable<V>接口中V call() throws Exception方法没有参数,故lambda表达式也不能有输入参数,
       * 返回类型为泛型,故lambda主体需要返回指定Integer类型
       *  2、因为.call()方法抛出异常,所以需要抛出或者捕获异常
       *  3、lambda表达式使用外部参数,需要是final类型,及时外部参数没有定义为final类型,
       * 也会隐式的指定为final,故值或者引用地址不能修改。
       */
      Callable<Integer> call = () -> value;
      System.out.println("无参的方法,所以lambda的参数列表中不能传递参数:" + call.call());
    } catch (Exception e) {
      e.printStackTrace();
    }

    lambda示例二:

    public class Java8Tester { 
    
      public static void main(String args[]){ 
        Java8Tester tester
    = new Java8Tester();     // 类型声明     MathOperation addition = (int a, int b) -> a + b;     // 不用类型声明     MathOperation subtraction = (a, b) -> a - b;     // 大括号中的返回语句     MathOperation multiplication = (int a, int b) -> { return a * b; };     // 没有大括号及返回语句     MathOperation division = (int a, int b) -> a / b;     System.out.println("10 + 5 = " + tester.operate(10, 5, addition));     System.out.println("10 - 5 = " + tester.operate(10, 5, subtraction));     System.out.println("10 x 5 = " + tester.operate(10, 5, multiplication));     System.out.println("10 / 5 = " + tester.operate(10, 5, division));     // 不用括号     GreetingService greetService1 = message -> System.out.println("Hello " + message);     // 用括号     GreetingService greetService2 = (message) -> System.out.println("Hello " + message);     greetService1.sayMessage("Runoob");     greetService2.sayMessage("Google");   }

      // 定义接口和接口中为实现的方法   
    interface MathOperation {
        int operation(int a, int b);
      }

      // 定义接口和接口中为实现的方法
      interface GreetingService {
        void sayMessage(String message);
      }

      // 定义方法,方法通过lambda表达式实现了接口中的方法   
    private int operate(int a, int b, MathOperation mathOperation){     return mathOperation.operation(a, b);   } }

    执行以上代码,输出结果为:

    10 + 5 = 15
    10 - 5 = 5
    10 x 5 = 50
    10 / 5 = 2
    Hello Runoob
    Hello Google

    使用 Lambda 表达式需要注意以下两点:

    Lambda表达式主要用来定义行内执行的方法类型接口,例如,一个简单方法接口。在上面例子中,我们使用各种类型的Lambda表达式来定义MathOperation接口的方法。然后我们定义了sayMessage的执行。

    Lambda 表达式免去了使用匿名方法的麻烦,并且给予Java简单但是强大的函数化的编程能力。

    Lambda表达式常用的场景是:函数式接口。函数式接口是指的只有一个抽象方法的接口,我们常用的函数式接口有:

    Runnable、Callable、PrivilegedAction、Comparator、FileFilter、PathMatcher、InvocationHandler、PropertyChangeListener、ActionListener、ChangeListener、Function、Predicate、BinaryOperator

    三、lambda表达式中的变量作用域

    lambda表达式只能引用标记了final的外层局部变量,这就是说不能在lambda内部修改定义在域外的局部变量,否则会编译错误。

    Java8Tester.java 文件输入以下代码:

    public class Java8Tester {
    
      final static String salutation = "Hello! "; 
    
      public static void main(String args[]){
        GreetingService greetService1
    = message -> System.out.println(salutation + message);     greetService1.sayMessage("Runoob");     //====================相当于下面==============================     GreetingService g = new GreetingService() {       @Override       public void sayMessage(String message) {         System.out.println(salutation + message);       }     };     g.sayMessage("jack");
      }   
    interface GreetingService {     void sayMessage(String message);   } }

    执行以上脚本,输出结果为:

    $ javac Java8Tester.java 
    $ java Java8Tester
    Hello! Runoob
    Hello! jack

    我们也可以直接在 lambda 表达式中访问外层的局部变量:

    public class Java8Tester { 
    
      public static void main(String args[]) { 
        final int num = 1; 
        Converter<Integer, String> s = (param) -> System.out.println(String.valueOf(param + num)); 
        s.convert(2); // 输出结果为 3 
      } 
    
      public interface Converter<T1, T2> { 
        void convert(int i); 
      } 
    }

    lambda表达式的局部变量可以不声明为final,但是不可被后面的代码修改(即隐性的具有final 的语义)

    int num = 1;  
    Converter<Integer, String> s = (param) -> System.out.println(String.valueOf(param + num));
    s.convert(2);
    num = 5;  //报错信息:Local variable num defined in an enclosing scope must be final or effectively final

    Lambda 表达式当中不允许声明一个与局部变量同名的参数或者局部变量。

    String first = "";  
    Comparator<String> comparator = (first, second) -> Integer.compare(first.length(), second.length());  //编译会出错
  • 相关阅读:
    升级:Logical Upgrade升级MySQL5.6.26
    基于GTID恢复误篡改数据
    mysql迁移:ibd表空间迁移库表
    mysql迁移:xtrabackup迁移mysql5.7.32
    Pycharm最新激活码2019
    转载:Prometheus+Grafana搭建HBase监控仪表盘
    总结《Elasticsearch源码解析和优化实战》第一讲
    yarn resourcemanager调优
    presto安装和集成kerberos的hive
    转载:shell expect实战实例
  • 原文地址:https://www.cnblogs.com/yanzige/p/11133608.html
Copyright © 2011-2022 走看看