首页 > 编程语言 >Java lambda表达式的使用注意点

Java lambda表达式的使用注意点

时间:2022-11-26 10:35:14浏览次数:38  
标签:Java 变量 System println out 表达式 lambda

0 捕获自由变量

为了使lambda表达式看起来更像是函数式编程,可以在函数内部直接访问外部变量。lambda表达式具有一个特殊的能力,它可以捕获自由变量。

自由变量指的是lambda表达式外(之前)的变量,如:

String str = "Hello, lambda!";
() -> {
    System.out.println(str);
}

这里的str就是自由变量。

其实,匿名对象也有该功能:

String str = "Hello, lambda!";
FI2.fun(new FI() {
    @Override
    public void run() {
        System.out.println(str);
    }
});

lambda表达式只能够捕获某些特殊的自由变量:不可变变量(final变量或隐式final变量)。

在某种意义上,我们可以认为lambda表达式只能捕获被final修饰的自由变量。由于String本身就是不可变的,这里我们换个可变的来举例子:

final int a = 1;
() -> {
    System.out.println(a);
}

这意味着,该变量在声明之后,就不可以再重新赋值了。如果是基本数据类型,表示变量值不能再改变;如果是引用数据类型,表示引用的对象地址不能再改变。

通常,我们会省略final修饰符,即该变量为隐式final变量:

int a = 1;
() -> {
    System.out.println(a);
}

编译器会帮我们检查:

  • 如果该变量被lambda表达式捕获,那么它就不能被重新赋值(不可变变量)。
  • 如果该变量被重新,那么它就不能被lambda表达式捕获(可变变量)。

需要注意的是,被lambda表达式捕获的自由变量只能初始化一次。即便它是隐式final变量,在lambda表达式之前/之内/之后,都不能重新赋值:

int a = 1;
// a = 2; 报错
() -> {
    // a = 2; 报错
    System.out.println(a);
}
// a = 2; 报错

1 作用域

由于lambda表达式捕获自由变量的特殊能力,使得它具有十分特殊的作用域。

一方面,lambda表达式内部可以访问到之前的不可变自由变量;另一方面,lambda表达式之后不能访问到其内部定义的变量:

int a = 1;
() -> {
    System.out.println(a);	// 可以访问
    int b = 2;
}
// System.out.println(b); 报错

这让我们联想到其他编程语言,如JavaScript。不同的是,它的自由变量是可变的:

let a = 1;
function fun() {
    console.log(a);
    let b =2;
}
fun();	// 1
b;	// VM273:1 Uncaught ReferenceError: b is not defined
a = 3;
fun();	// 3

lambda表达式本质上是动态创建的匿名对象,其方法体为对象实例的方法体。而此时在编译器的帮助下竟然可以在对象内部访问到外部的变量。这对以往的思维可能有很大的颠覆。

2 this/super

由于lambda表达式捕获自由变量的特殊能力,它总能够捕获外部的thissuper

因此,在lambda表达式中使用thissuper关键字时,指的是创建这个lambda表达式所在的方法中的thissuper对象。

public class LambdaScope {
    static interface FI {
        void run();
    }
    static class FI2 {
        static void fun(FI fi) {
            fi.run();
        }
    }
    public void test() {
        FI2.fun(() -> {
            // class lambda.LambdaScope
            System.out.println(this);
            // class lambda.LambdaScope
            System.out.println(super.getClass());
        });
    }
}

这里的thissuper指的是test()方法中的thissuper

3 可变自由变量

在某些情况下,lambda表达式中既需要获取外部的自由变量,同时又要求该变量可以重新赋值。

这种情况下可以将该自由变量提升为全局唯一的变量,如静态变量。

public class LambdaScope {
    public static int count = 0;
    static interface FI {
        void run();
    }
    static class FI2 {
        static void fun(FI fi) {
            fi.run();
        }
    }
    public static void demo05() {
        FI2.fun(() -> {
            LambdaScope.count++;
        });
    }
}

但是,此时需要考虑并发执行多个lambda表达式时的不安全问题。

标签:Java,变量,System,println,out,表达式,lambda
From: https://www.cnblogs.com/Xianhuii/p/16927006.html

相关文章

  • Java方法引用和构造器引用详细解释
    1什么是方法/构造器引用简单来说,方法引用是对lambda表达式的一种更加简便的写法。所谓引用,就是对当前已存在的一段代码的借用。方法引用则是隐式借用已经存在的方法作......
  • 小新学Java11
    一、异常1.1异常概念异常︰指的是程序在执行过程中,出现的非正常的情况,最终会导致JVM的非正常停止。在Java等面向对象的编程语言中,异常本身是一个类,产生异常就是创建异常......
  • 为什么要使用Java Stream API?
    Stream是Java8提供的一种更加简便的,对集合类型数据结构的处理API。这里的集合类型数据结构包括各种数组(int[]/String[]等),也包括Collection和Map等实现类。1传统方式操作......
  • 深入剖析Java Stream底层源码
    1Stream的使用在深入学习Stream的本质之前,我们需要先熟悉Stream的使用规则。对Stream有了整体的认识之后,才能更好的理解它的本质。1.1使用步骤使用Stream只需要遵循3......
  • Java.11.26
    一1..breakcontinue1.1.break在任何循环语句的主体部分,均可用break控制循环的流程。break用于强行退出循环,不执行循环中剩余的语句。(break语句也在switc......
  • java使用Jsch/ssh2实现从linux服务端遍历文件名以及文件内容回显到客户端
    java使用Jsch/ssh2实现从linux服务端遍历文件名以及文件内容回显到客户端这里只我上传的是测试类,需改下参数直接用就行。jsch依赖: <dependency>            ......
  • Java connect to SSH2
    GanymedSSH-2(ch.ethz.ssh2)爱码者于 2020-09-2111:17:18 发布6102 收藏 10分类专栏: 项目实践版权 项目实践专栏收录该内容15篇文章0订阅订阅......
  • java简单解析wsdl文件
    1packagecom.example.demo.api.soap.client.userInterface.controller;234importorg.w3c.dom.Document;5importorg.w3c.dom.NamedNodeMap;6importor......
  • Java JDK11的下载与安装
    前言本篇文章是基于win10系统下载安装JDK11的教程。1.下载OracleJDK进入Oracle官网:https://www.oracle.com/java/technologies/downloads/#java11选择Java11→Winodws→......
  • Java8新特性
    Java8NashornJavaScriptJava8新特性Java8新特性Nashorn一个javascript引擎。NashornJavaScriptEngine在Java15已经不可用了。这已经在Java11标记为:@de......