• Lambda 表达式基础理论与示例


    Lambda 表达式基础理论与示例

    Lambda 表达式,也可称为闭包,推动 Java 8 发布的最重要新特性。

    Lambda 允许把函数作为一个方法的参数(函数作为参数传递进方法中)。

    使用 Lambda 表达式可以使代码变的更加简洁紧凑。

    语法

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

    (parameters) -> expression

    (parameters) ->{ statements; }

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

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

    可选的参数圆括号:一个参数无需定义圆括号,但多个参数需要定义圆括号。

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

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

    Lambda 表达式实例

    Lambda 表达式的简单例子:

    // 1. 不需要参数,返回值为 5 

    () -> 5 

    // 2. 接收一个参数(数字类型),返回其2倍的值 

    x -> 2 * x 

    // 3. 接受2个参数(数字)返回差值 

    (x, y) -> x – y 

    // 4. 接收2个int型整数,返回和 

    (int x, int y) -> x + y 

    // 5. 接受一个 string 对象在控制台打印,不返回任何值(看起来像是返回void) 

    (String s) -> System.out.print(s)

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

    Java8Tester.java 文件

    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);

       }

       

       private int operate(int a, int b, MathOperation mathOperation){

          return mathOperation.operation(a, b);

       }

    }

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

    $ javac Java8Tester.java

    $ java Java8Tester

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

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

    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");

       }

       

       interface GreetingService {

          void sayMessage(String message);

       }

    }

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

    $ javac Java8Tester.java

    $ java Java8Tester

    Hello! Runoob

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

    Java8Tester.java 文件

    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());  //编译会出错

     

    Java的方法分为实例方法,例如Integer定义的equals()方法:

     

    public final class Integer {

        boolean equals(Object o) {

            ...

        }

    }

    以及静态方法,例如Integer定义的parseInt()方法:

    public final class Integer {

        public static int parseInt(String s) {

            ...

        }

    }

    无论是实例方法,还是静态方法,本质上都相当于过程式语言的函数。例如C函数:

    char* strcpy(char* dest, char* src)

    只不过Java的实例方法隐含地传入了一个this变量,即实例方法总是有一个隐含参数this。

    函数式编程(Functional Programming)是把函数作为基本运算单元,函数可以作为变量,可以接收函数,还可以返回函数。历史上研究函数式编程的理论是Lambda演算,所以经常把支持函数式编程的编码风格称为Lambda表达式。

    Lambda表达式

    在Java程序中,经常遇到一大堆单方法接口,即一个接口只定义了一个方法:

    Comparator

    Runnable

    Callable

    以Comparator为例,想要调用Arrays.sort()时,可以传入一个Comparator实例,以匿名类方式编写如下:

    String[] array = ...

    Arrays.sort(array, new Comparator<String>() {

        public int compare(String s1, String s2) {

            return s1.compareTo(s2);

        }

    });

    上述写法非常繁琐。从Java 8开始,可以用Lambda表达式替换单方法接口。改写上述代码如下:

    // Lambda

    import java.util.Arrays;

    public class Main {

        public static void main(String[] args) {

            String[] array = new String[] { "Apple", "Orange", "Banana", "Lemon" };

            Arrays.sort(array, (s1, s2) -> {

                return s1.compareTo(s2);

            });

            System.out.println(String.join(", ", array));

        }

    }

     Run

    观察Lambda表达式的写法,它只需要写出方法定义:

    (s1, s2) -> {

        return s1.compareTo(s2);

    }

    其中,参数是(s1, s2),参数类型可以省略,因为编译器可以自动推断出String类型。-> { ... }表示方法体,所有代码写在内部即可。Lambda表达式没有class定义,因此写法非常简洁。

    如果只有一行return xxx的代码,完全可以用更简单的写法:

     

    Arrays.sort(array, (s1, s2) -> s1.compareTo(s2));

    返回值的类型也是由编译器自动推断的,这里推断出的返回值是int,因此,只要返回int,编译器就不会报错。

    FunctionalInterface

    把只定义了单方法的接口称之为FunctionalInterface,用注解@FunctionalInterface标记。例如,Callable接口:

    @FunctionalInterface

    public interface Callable<V> {

        V call() throws Exception;

    }

    再来看Comparator接口:

    @FunctionalInterface

    public interface Comparator<T> {

        int compare(T o1, T o2);

        boolean equals(Object obj);

        default Comparator<T> reversed() {

            return Collections.reverseOrder(this);

        }

        default Comparator<T> thenComparing(Comparator<? super T> other) {

            ...

        }

        ...

    }

    虽然Comparator接口有很多方法,但只有一个抽象方法int compare(T o1, T o2),其他的方法都是default方法或static方法。另外注意到boolean equals(Object obj)是Object定义的方法,不算在接口方法内。因此,Comparator也是一个Functional Interface。

     

    参考链接:

    https://www.runoob.com/java/java8-lambda-expressions.html

    https://www.liaoxuefeng.com/wiki/1252599548343744/1305158055100449

     

    人工智能芯片与自动驾驶
  • 相关阅读:
    strncpy (Strings) – C 中文开发手册
    HTML track label 属性
    Java面试题:常用的Web服务器有哪些?
    鲲鹏920上安装ovs
    基于AC控制器+VXLAN解决方案
    二层MAC学习及BUM报文转发
    基于mac表的vxlan转发
    Agile Controller vxlan
    设置鲲鹏916/920通过pxe安装os
    ovs-vxlan&vlan
  • 原文地址:https://www.cnblogs.com/wujianming-110117/p/15491870.html
Copyright © 2020-2023  润新知