Linux软件安装 全局重载运算符 list 建筑资质 git视频教程 nginx默认端口号 java通用版qq浏览器下载 ab软启动器 matlab颜色代码 java解析pdf java高级特性 mysql新建数据库 python随机函数 python创建数据库 python函数的调用 java斐波那契数列 数据结构java版 java中的基本数据类型 java中基本数据类型 java中接口的定义 java结束线程 javahttp 怎么装linux系统 php开发教程 黑客攻防实战入门 莫莫小工具 unix操作系统下载 linux操作系统原理 高效能人士的七个习惯下载 rndis驱动下载 字幕提取 生存猎人属性 ram容量是什么意思 微信砍价活动怎么做 R语言初学者指南 亚索刀光 layout下载 神牧属性 例外被抛出且未被接住 编写软件
当前位置: 首页 > 学习教程  > 编程语言

Java 8|优秀的Lambda表达式

2020/12/28 19:17:04 文章标签:

1、Lambda简介 从Java8出现以来lambda是最重要的特性之一,它可以让我们用简洁流畅的代码完成一个功能。 Lambda 表达式是函数式编程的的一个重要特性,标志着 Java 向函数式编程迈出了重要的第一步。 2、Lambda 表达式初体验 Java 8之前写代码&#x…

1、Lambda简介

从Java8出现以来lambda是最重要的特性之一,它可以让我们用简洁流畅的代码完成一个功能。

Lambda 表达式是函数式编程的的一个重要特性,标志着 Java 向函数式编程迈出了重要的第一步。

2、Lambda 表达式初体验

Java 8之前写代码:

Runnable r = new Runnable() {
    @Override
    public void run() {
        System.out.println("你好、二哥!");
    }
}

用Lambda表达式之后:

Runnable r =() -> System.out.println("你好,二哥!我是Lambda表达式。");

没有对比、没有伤害、是不是很优秀?

3、Lambda 表达式语法

image-20201107225921198

语法结构如下:

parameter -> expression body

Java8中引入了一个新的操作符 "->" 该操作符称为箭头操作符或 Lambda 操作符

箭头操作符将 Lambda 表达式拆分成两部分:

左侧:Lambda 表达式的参数列表
右侧:Lambda 表达式中所需执行的功能, 即 Lambda 体

伪代码:

//有参数且只有一条语句时
int sum = (x,y) -> x + y
//只有一个参数时
x -> x
//没有参数时
() -> System.out.println("你好,二哥!我是Lambad表达式。")
//有多条语句时
(x,y) -> {
    int z = x + y;
    System.out.println("你好,二哥!我是Lambad表达式。")
}

注:

  • 可选的参数类型声明 :无需声明参数的类型。编译器可以从参数的值推断出相同的值。
  • 选的参数周围的小括号 () :如果只有一个参数,可以忽略参数周围的小括号。但如果有多个参数,则必须添加小括号。
  • 可选的大括号 {} : 如果 Lambda 表达式只包含一条语句,那么可以省略大括号。但如果有多条语句,则必须添加大括号。
  • 可选的 return 关键字 :如果 Lambda 表达式只有一条语句,那么编译器会自动 return 该语句最后的结果。但如果显式使用了 return 语句,则必须添加大括号 {} ,哪怕只有一条语句。

4、Lambda 表达式的原理

Lambda 表达式其实是一个特殊的只有一个方法的类的实例。

这些类是 Java 8 内部已经定义好的,而且实现了 java.lang.FunctionalInterface 这个接口。

这个 java.lang.FunctionalInterface 接口是一种信息性注解类型,

用于标识一个接口类型声明为函数接口( functional interface )。

从某些方面说,Java 8 的 Lambda 表达式是使用匿名内部类的语法创建了 jav****a.util.function 包下相应签名的接口的或者其它自定义的只有一个方法的接口实例。

实际上,Java 8 中的 Lambda 不仅仅是使用匿名内部类,还使用了 Java 8 接口的默认方法和一些其它的功能。

代码范例:

package com.sjh.test.java8;

public class TestLambda {

    public static void main(String args[])
    {
        TestLambda tester = new TestLambda();

        // 有声明参数类型
        MathOperation addition = (int a, int b) -> a + b;

        // 没有声明参数类型
        MathOperation subtraction = (a, b) -> a - b;

        // 使用 return 语句显式返回值需要添加大括号
        MathOperation multiplication = (int a, int b) -> { return a * b; };

        // 如果只有一条语句,那么可以省略大括号,Java 会返回表达式的值
        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));
    }

    interface MathOperation {
        int operation(int a, int b);
    }

    private int operate(int a, int b, MathOperation mathOperation) {
        return mathOperation.operation(a, b);
    }
}

运行结果:

/Library/Java/JavaVirtualMachines/jdk1.8.0_171.jdk/... com.sjh.test.java8.TestLambda
10 + 5 = 15
10 - 5 = 5
10 x 5 = 50
10 / 5 = 2

Process finished with exit code 0

总结:为那些函数接口定义了它们包含的唯一方法,而且返回函数接口的实例

Lambda 表达式的缺点

Java Lambda 表达式最大的缺点,就是不能像其它语言的 Lambda 表达式一样凭空出现。

Java 中的 Lambda 表达式需要有一个函数接口声明作为模板。这个模板定义了 Lambda 表达式的参数类型和返回值类型。

例如下面的代码,我们先要声明一个函数接口类型,然后才能定义一个参数和返回值都一样的表达式

代码范例:

package com.sjh.test.java8;

public class TestLambdaFirst {

    // 先声明一个函数接口
    interface GreetingService {
        void sayMessage(String message);
    }

    public static void main(String args[])
    {
        TestLambdaFirst tester = new TestLambdaFirst();

        // 有小括号
        GreetingService greetService1 = message ->
                System.out.println("你好," + message);

        // 省略小括号
        GreetingService greetService2 = (message) ->
                System.out.println("你好," + message);

        greetService1.sayMessage("二哥!");
        greetService2.sayMessage("我是Lambda。");
    }
}

运行结果:

/Library/Java/JavaVirtualMachines/jdk1.8.0_171.jdk/...com.sjh.test.java8.TestLambdaFirst
你好,二哥!
你好,我是Lambda。

Process finished with exit code 0

5、Lambda 表达式作用域(scope)

因为 Java 8 的 Lambda 表达式其实是函数接口的内联实现,也就是匿名内部类。因此,可以引用任何外部的变量或者常量。

但是Lambda 对这些外部的变量是有要求的:它们必须使用 final 修饰符修饰。如果一个变量允许被第二次赋值,则 Lambda 表达式会抛出编译错误。

表达式使用外部 final 变量:

package com.sjh.test.java8;

public class TestLambdaSecond {

    static String salutation = "你好,";

    public static void main(String args[])
    {
        GreetingService greetService = message ->
                System.out.println(salutation + message);
        greetService.sayMessage("二哥!我是Lambda。");
    }

    interface GreetingService {
        void sayMessage(String message);
    }
}

运行结果:

/Library/Java/JavaVirtualMachines/jdk1.8.0_171.jdk/... com.sjh.test.java8.TestLambdaSecond
你好,二哥!我是Lambda。

Process finished with exit code 0

Lambda 引用的普通的变量也是可以的,只要这个变量没有第二次被赋值,不管是任何地方。

package com.sjh.test.java8;

public class TestLambdaThree {

    static String salutation = "你好,";

    public static void main(String args[])
    {
        GreetingService greetService = message ->
                System.out.println(salutation + message);
        greetService.sayMessage("二哥!我是Lambda。");
    }

    interface GreetingService {
        void sayMessage(String message);
    }
}

运行结果:

/Library/Java/JavaVirtualMachines/jdk1.8.0_171.jdk/...com.sjh.test.java8.TestLambdaThree
你好,二哥!我是Lambda。

Process finished with exit code 0

如果 lambda 表达式引用的是当前作用域下的普通的变量,而该变量又在某个地方第二次被赋值,则会抛出一个编译错误。

package com.sjh.test.java8;

public class TestLamdbaFour {

    public static void main(String args[])
    {
        String salutation = "你好,";

        GreetingService greetService = message ->
                System.out.println(salutation + message);
        greetService.sayMessage("二哥!我是Lambda。");
        salutation = "Hello,";
    }

    interface GreetingService {
        void sayMessage(String message);
    }
}

错误提示:

Information:java: Errors occurred while compiling module 'test'
Information:javac 1.8.0_171 was used to compile java sources
Information:2020-05-27 12:39 - Build completed with 1 error and 0 warnings in 2 s 758 ms
/Users/sunjiahao/Develop/gitee_project/test/src/com/sjh/test/java8/TestLamdbaFour.java
Error:(10, 36) java: 从lambda 表达式引用的本地变量必须是最终变量或实际上的最终变量

如果 lambda 表达式引用的变量并不是当前作用域下声明的,也可以随意赋值,并不会报错

package com.sjh.test.java8;

public class TestLambdaFive {

    static String salutation = "你好,";

    public static void main(String args[])
    {
        salutation = "Hello,";
        GreetingService greetService = message ->
                System.out.println(salutation + message);
        greetService.sayMessage("二哥!我是Lambda。");
        salutation = "你好,";
    }

    interface GreetingService {
        void sayMessage(String message);
    }
}

运行结果:

/Library/Java/JavaVirtualMachines/jdk1.8.0_171.jdk/...com.sjh.test.java8.TestLambdaFive
Hello,二哥!我是Lambda。

Process finished with exit code 0

总结:

Java lambda 表达式可以随意引用外部变量,但如果外部变量是在当前作用域声明的,则一定不可以进行第二次赋值,哪怕是在 Lambda 语句之后。


本文链接: http://www.dtmao.cc/news_show_550187.shtml

附件下载

相关教程

    暂无相关的数据...

共有条评论 网友评论

验证码: 看不清楚?