从lombok的val和var到JDK的var关键字方式

 更新时间:2024年05月21日 08:54:59   作者:初心绘流年  
这篇文章主要介绍了从lombok的val和var到JDK的var关键字方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教

前言

近期因项目中的开源框架版本升级导致项目的整体jdk版本被迫从万年的java8升级到了java11

于是我们也从该开源框架中看到了对于我来说一个比较陌生的身影—val,于是便开始一小波的学习

在这里插入图片描述

一、Lombok中的val和var

1.1 lombok.val

首先看官方文档介绍:

You can use val as the type of a local variable declaration instead of actually writing the type. When you do this, the type will be inferred from the initializer expression. The local variable will also be made final. This feature works on local variables and on foreach loops only, not on fields. The initializer expression is required.

val is actually a ‘type’ of sorts, and exists as a real class in the lombok package. You must import it for val to work (or use lombok.val as the type). The existence of this type on a local variable declaration triggers both the adding of the final keyword as well as copying the type of the initializing expression which overwrites the ‘fake’ val type.

WARNING: This feature does not currently work in NetBeans.

大致的意思就是val是用于声明局部变量的,它会根据初始化的表达式来对变量类型进行推断。使用val的局部变量会被声明为final的,它可以使用与foreach的循环中,val不可以用于成员变量,并且它的初始化表达式是必须的(即必须在声明的时候给出初始化的表达式)。

使用示例:

public static void main(String[] args){
    val map = new HashMap<>();
    map.put("name","dachengcheng");
    map.put("gender","boy");
    map.put("obj", new Object());

    for (val entry:map.entrySet()){
        System.out.println(entry.getKey()+":"+entry.getValue());
    }
}

其实val就是一种类型推断的语法糖,在编译之后会进行desugar的,我们来看一下以上代码经过编译之后变成什么样子

// 以下是JDK11反编译出来的
public static void main(String[] args) {
    HashMap<Object, Object> map = new HashMap();
    map.put("name", "dachengcheng");
    map.put("gender", "boy");
    map.put("obj", new Object());
    Iterator var2 = map.entrySet().iterator();

    while(var2.hasNext()) {
        Entry<Object, Object> entry = (Entry)var2.next();
        PrintStream var10000 = System.out;
        ((PrintStream)entry.getKey()).println((String)entry.getValue());
    }

}

因为我们在泛型中并未指定具体的类型,所以类型推断出来的就是HashMap<Object,Object>的类型了,我们可以看到在循环中,也是很正确的推断出了Entry类型。

上面不是提到val代表的是final类型的局部变量吗?为啥反编译出来的没有看到final的字样?

这一点其实我也很疑惑,不知道是不是因为IDEA的工具反编译问题,或者是因为Java8以上的Effective final的特性导致的没有final修饰,但实际是final类型呢?

我们降低一下jdk版本(JDK6)试了一下,发现结果仍然一样,资料找了大半圈没找到一个人有合适的说法。于是我试了一下直接用final关键字修饰局部变量

在这里插入图片描述

在这里插入图片描述

才发现是局部变量的final并没有写入class文件中,至于为什么,大概是优化吧,具体的可能得去看看虚拟机相关的知识了,此处暂且不深入了。

局部变量以及参数中的final,同样不能提升我们的性能,它甚至不会被写进字节码中

1.2 lombok.var

还是来看官方文档的介绍

var works exactly like val, except the local variable is not marked as final.

The type is still entirely derived from the mandatory initializer expression, and any further assignments, while now legal (because the variable is no longer final), aren’t looked at to determine the appropriate type.For example, var x = "Hello"; x = Color.RED; does not work; the type of x will be inferred to be java.lang.String and thus, the x = Color.RED assignment will fail. If the type of x was inferred to be java.lang.Object this code would have compiled, but that’s not howvar works.

大致意思就是varval很像,只不过它标记的局部变量并不是final的。

二、Java中的var关键字

2.1 如何使用?

var关键字其实作用和上面提到的lombok.vallombok.var是一样的,也是用于局部变量的类型推断;var修饰的变量是非final的,如果需要final可以加上final修饰符。

还是一样我们来看一下源码和编译之后的class文件内容

源码

public class ValDemo {
    final String bbb ="111";

    public static void main(String[] args){
        var map = new HashMap<String,String>();
        map.put("aaa","dachengcheng");
        var obj = getObj();
    }
    private static List<List<Map<String, List<Map<String,String>>>>> getObj(){
        // 当然现实当中这种返回类型容易被打死,此处只是为了效果演示
        return null;
    }
}

反编译

public class ValDemo {
    final String bbb = "111";

    public ValDemo() {
    }
    public static void main(String[] args) {
        HashMap<String, String> map = new HashMap();
        map.put("aaa", "dachengcheng");
        List<List<Map<String, List<Map<String, String>>>>> obj = getObj();
    }
    private static List<List<Map<String, List<Map<String, String>>>>> getObj() {
        return null;
    }
}

2.2 为什么推出var关键字?

Java作为一个强类型的静态类型语言,为啥要推出这么一个关键字呢?

我们知道在JavaScript这种弱类型的语言中有var关键字,我想大概是因为“偷懒”吧。

我们知道Java代码存在很多模版化的声明,如HasMap<String,String> map = new HashMap<String,String>(), 这种写法虽然给我们带来了好处的同时,也带来了一些书写上的繁琐,有些人可能觉得花时间在书写这种模板代码上是在浪费时间,为啥Java就不能帮我们完成这个事呢? 比如上面提到的List<List<Map<String, List<Map<String,String>>>>>返回类型,真正要写的那可是一长串,有了var关键字之后就简单多了,直接var obj = getObj();,在这种情况下相对来说代码更简单,至于易读性是相对的,有的时候提高了可读性,有的时候反而不方便。

当然官方对于这个关键字的由来,大概是因为关于 2016 年有一个 JDK 增强提议(JEP)在 Java 社区引起了轰动:JEP 286,感兴趣的可以去了解一下。

三、该如何抉择呢?

其实该使用谁那完全看个人喜好了,但是呢我们必须得了解清楚他们之间的区别,比如lombok.val在书写的时候,IDE可能还无法识别它的final特性,可以针对该局部变量进行修改,只会在编译或运行的时候发现报错。

而且有的团队可能会比较抵制lombok,理由大概是一人用lombok,所有人都得用,在某种程度上属于强买强卖。

所以如果在JDK版本允许的情况下(JDK10及以上),我们可以考虑用jdk自带的var关键字。

如果是万年java8的话,又想使用这种语法特性,那么就可以使用lombok.val了。

Reference:

总结

以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。

相关文章

  • Java中的循环笔记整理(必看篇)

    Java中的循环笔记整理(必看篇)

    下面小编就为大家带来一篇Java中的循环笔记整理(必看篇)。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2017-06-06
  • Java中数组的一些常见操作和技巧分析

    Java中数组的一些常见操作和技巧分析

    这篇文章主要给大家介绍了关于Java中数组的一些常见操作和技巧分析的相关资料,数组(Array)是Java中的一种引用数据类型,是多个相同类型数据一定顺序排列的集合,并使用一个名字命名,并通过编号的方式对这些数据进行统一管理,需要的朋友可以参考下
    2023-08-08
  • Jmeter工作原理及常见错误解析

    Jmeter工作原理及常见错误解析

    这篇文章主要介绍了Jmeter工作原理及常见错误解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2020-09-09
  • 关于SpringBoot配置文件加载位置的优先级

    关于SpringBoot配置文件加载位置的优先级

    这篇文章主要介绍了关于SpringBoot配置文件加载位置的优先级,我们也可以通过spring.config.location来改变默认的配置文件位置,项目打包好后,我们可以通过命令行的方式在启动时指定配置文件的位置,需要的朋友可以参考下
    2023-10-10
  • 初识Java设计模式适配器模式

    初识Java设计模式适配器模式

    这篇文章主要为大家详细介绍了Java设计模式适配器模式,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2016-09-09
  • 使用@EnableWebMvc轻松配置Spring MVC

    使用@EnableWebMvc轻松配置Spring MVC

    这篇文章主要为大家介绍了使用@EnableWebMvc轻松配置Spring MVC实现示例解析,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-10-10
  • 用Java进行zip文件压缩与解压缩

    用Java进行zip文件压缩与解压缩

    这篇文章主要介绍了用Java进行zip文件压缩与解压缩的方法,帮助大家更好的理解和使用Java,感兴趣的朋友可以了解下
    2020-12-12
  • java 分布式与集群的区别和联系

    java 分布式与集群的区别和联系

    本文主要介绍了java分布式与集群的区别和联系,具有很好的参考价值,下面跟着小编一起来看下吧
    2017-02-02
  • Java并发系列之AbstractQueuedSynchronizer源码分析(概要分析)

    Java并发系列之AbstractQueuedSynchronizer源码分析(概要分析)

    这篇文章主要为大家详细介绍了Java并发系列之AbstractQueuedSynchronizer源码,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2018-02-02
  • SpringBoot2零基础到精通之数据库专项精讲

    SpringBoot2零基础到精通之数据库专项精讲

    SpringBoot是一种整合Spring技术栈的方式(或者说是框架),同时也是简化Spring的一种快速开发的脚手架,本篇我们来学习如何连接数据库进行操作
    2022-03-03

最新评论