java变量命名规则_浅谈JAVA开发规范与开发细节(上)

04a327a4427434f75b14ae51f021c9f6.gif

开发团队在开发过程中,由于每个人的开发习惯,以及对于技术的理解深浅程度不一,往往一个项目在开发过程中,代码的质量,代码的风格都不尽相似,所以有一份适合团队的代码规范是非常有必要的,而一个团队的代码规范,包含了开发常见的风格习惯以及一些常见代码细节的写法规范等,本篇就来浅谈一些代码规范涉及的技术细节和对这些部分的思考。

命名规范

相信经历过项目开发的人都知道,在开发过程中会涉及无数次的申明操作,这个过程中最让人头疼的就是给申明的文件(实例)起个名字了。名字需要准确的表达出背后代表的含义,并且还要通俗易懂,使得代码干净漂亮,否则不好的命名反而成为开发的阻碍,干扰维护者和开发者的思路。那么一个好的命名会给我们开发带来什么好处呢?

  1. 为标识符提供附加的信息,赋予标识符现实意义。帮助我们理顺编码的逻辑,减少阅读和理解代码的工作量;

  2. 使代码审核变得更有效率,专注于更重要的问题,而不是争论语法和命名规范这类小细节,提高开发效率;

  3. 提高代码的清晰度、可读性以及美观程度;

  4. 避免不同产品之间的命名冲突。

那么常见的命名方式有哪些呢?根据各大规范和Java框架主流的方案来说,一般分为四种:

驼峰命名法

驼峰命名法基本上是各大企业使用最多,也是各大规范首推的命名方式。其使用大小写混合的格式,单词之间不使用空格隔开或者连接字符连接的命名方式,因此发展处两种格式:大驼峰命名法(UpperCamelCase)和小驼峰命名法(lowerCamelCase)

这两种命名方式的区别主要在第一个单词的首字母上,大驼峰命名法则是首字母大写命名,而小驼峰则是首个单词的首字母小写,比如:firstName, toString等。在jdk中参照了谷歌制定的驼峰命名转换规则,用来细分不同情况下的驼峰转换:

1.从正常的表达形式开始,把短语转换成 ASCII 码,并且移除单引号,如“Müller’s algorithm”转换为“Muellers algorithm”

2.如果存在连接符号,就将连接符开始分割为两个单词,如果某个分割前某个单词已经是驼峰命名,也拆分为小写的两个单词,如:AdWords会转换为ad words,而non-current则转换为non current 等

3.将所有的字母转为小写字母,每个单词的首字母大写,就转换为了大驼峰命名/首字母小写则转为小驼峰

4.将所有的单词连接在一起,即为标示符命名

例如下面的转换案例:

8bf660706951e998f83257de8a622aa5.png

蛇形命名法

蛇形命名法在Java中极少见到,一般为每个单词之间都通过‘’进行连接,例如‘outof’

串式命名法

串式命名法和蛇形规则一样,唯一区别是,每个单词之间通过'-'连接,例如'out-of'

匈牙利命名法

匈牙利命名法在Java早期的框架中开始出现,由一个或者多个小写字母开始,使用这些字母作为标示符,用来标记当前命名的变量的用途,例如:usName(表示是用户的名称),lAccountNum(表示是Long类型的长整数)等

而在jdk中,针对每一种类型的命名有特定的规范,针对每一种编码规范来组合使用在不同场景的命名中,如下:

6a643a0e69b033878bb15561af4ea29c.png

总结下来,jdk命名遵循了三点:

1.命名有准确的意义,绝不使用单词缩写或者单词的部分,例如GoodsItem,绝不会命名为GdItem

2.严格遵守命名规范,决不允许一个规则内出现多个规范混用的情况,例如在一个命名中同时出现驼峰命名与蛇形命名等

3.尽量将可读性的命名放在前面,开发者的习惯一般都是从左到右开始阅读和编码,所以将能体现出想要的信息的内容优先放在前面,例如BeijingTime和TimeBeijing的区别

变量申明的时机

前面我们说过命名的规范,那么申明变量是否也需要规范呢?其实也需要,例如现在申明一个类型的变量的时候,往往有人喜欢一个类型的变量在一行内申明完毕,例如:

int size, length;

甚至于出现了一行申明了七八个属性的情况,或者是在一行内申明了好几个类型的变量,例如:

int size,entity[];//一行申明多个不同类型变量

看起来代码似乎节省了,但是对于开发和维护来说,其实反而更容易忽略错误,更重要的是申明类型是数组的时候不要把基本类型和[]分开,因为int[] 才是代表了一个类型的整体,分开申明容易被忽略,或者埋下隐患的错误,所以往往建议每一行仅申明一个变量,如下:

int size;

int[] entity;

在开发中往往还存在另外一个情况,就是方法内申明局部变量的时候,往往喜欢在方法开始的时候就创建或者申明该变量,但是使用的时机往往在n行代码以后,甚至于到后面这个申明的变量并没有使用到,由于间隔太远,也没有关注,后面就成了一个死变量,这种情况是很多见的,而反观jdk的规范中,可以看到都是在需要使用变量的时候创建,或者在需要使用的前几行代码申明再去创建,例如:

public void test(String userName){

Account userAccount;

String groceryStoreName;

//中间一堆业务代码和操作

/*****

****

***/

//通过用户名获取userAccount

userAccount = AccountManager.getUserAccount(userName);

if(userAccount == null){

//为null的操作,抛异常

}

//再去获取名称

groceryStoreName = userAccount.getGroceryStoreName();

if(groceryStoreName == null){

//为null,抛异常

}

//后续一堆业务代码

}

但是我们看下规范后的写法:

public void test(String userName){

//中间一堆业务代码和操作

/*****

****

***/

//通过用户名获取userAccount

Account userAccount = AccountManager.getUserAccount(userName);

if(userAccount == null){

//为null的操作,抛异常

}

//再去获取名称

String groceryStoreName = userAccount.getGroceryStoreName();

if(groceryStoreName == null){

//为null,抛异常

}

//后续一堆业务代码

}

很明显的可以看出来,代码更清晰明了,也更有逻辑性。另外在申明类属性变量的时候,我们建议将变量申明在一起,分块存放,不建议在类中变量和方法混合在一起使用,例如:

ce2013bc9d65587b3e05a21aecf0e1ba.png

另外在申明类变量的时候,切记不要忘记类变量如果是基础类型,会有默认值,如非必要,在类属性创建中建议使用包装类型,防止因默认值带来的数据不一致等问题,而在方法内创建局部变量的时候,由于基本类型变量没有默认值,需要手动申明值,反而建议使用基本类型,而不是使用包装类,这样同样也可以尽量避免无意的拆箱、装箱行为,在数十万次百万次的情况下,对于程序也会造成一定的影响。

if与大括号

if语句是我们开发中最常见的逻辑分支语句之一,同样的在java中if也会有一些简洁写法,例如逻辑业务仅有一行代码的时候,我们可以省去大括号,直接在if下一行编写业务代码,如下:

if(flag)

count ++;

//if以外的逻辑

user.setAge(10);

......

但是熟悉规范的都知道,无论是阿里规范还是jdk的规范,都不推荐使用简化代码,这是为什么呢?这让我想起了2014年苹果的ios系统爆出来的一个严重安全漏洞(“GoTo Fail 漏洞”),而这个漏洞就和大括号有关系,而对应漏洞的代码大概可以理解为这样:

if ((error = doSomething()) != 0)

goto fail;

//无论如何都是走到这里,下面再也触发不了了

goto fail;

if ((error= doMore()) != 0)

goto fail;

fail:

return error;

是不是看出来什么了?没错,如果前面的条件生效,就会跳转到fail的操作,返回error,但是如果不满足也会跳转到fail,那么也就是说后续的业务代码无论如何也触发不了了,其实了解这个问题的人其实大概可以猜出来,这里就是多写了一个goto fail;导致编译器认为了别的业务代码,但是假设我们加了大括号,这个问题就会迎刃而解,例如:

if ((error = doSomething()) != 0)

{

goto fail;

//无论如何都是走到这里,下面再也触发不了了

goto fail;

}

if ((error= doMore()) != 0)

goto fail;

fail:

return error;

其实这个时候就会发现即使是多写了一行代码,也不会影响整个业务的逻辑,减少了bug产生。看到这里我们似乎明白了,为什么各大规范都建议不省略大括号的写法了。

包装类与基本类型

做Java开发的都知道,Java中默认有八种基本类型,但是同样的也有八种对应的包装类型,很多时候企业开发和使用的时候对于包装类型和基本类型的使用并不规范,往往会导致一部分小的隐患的发生。前面我们有介绍建议在类属性申明的时候使用包装类型,而在方法内建议使用基本类型,这里我们可以再去思考两个开发的时候常用的使用场景:

1.判断两个数值类型的值是否相等

2.创建数值类型

看过阿里手册和JDK规范的应该知道,里面都有一条规范,明确指出基本数值类型的包装类型在比较的时候不允许使用==的方式,而是使用equals,这是为什么呢?我们来看看一个例子:

Integer a = 100, b = 100, c = 150, d = 150;

System.out.println(a == b);//true

System.out.println(c == d);//false

可以看到两个Integer类型的变量,值一样的情况下,==比较的结果居然是false?我们通过断点的方式知道 Integer var = ? 形式声明变量,会通过 java.lang.Integer#valueOf(int) 来构造 Inte ger 对象,我们来看看valueOf方法的源码:

public static Integer valueOf(int i) {

if (i >= IntegerCache.low && i <= IntegerCache.high)

return IntegerCache.cache[i + (-IntegerCache.low)];

return new Integer(i);

}

可以看到,会去判断value的值是否在IntegerCache的范围内,如果在,就会使用IntegerCache中缓存的实例,不存在才会创建新的Integer实例,这个缓存的值,默认是-128到127之间,并且是可以通过配置环境变量的方式动态改变的,这点可以从IntegerCache源码中看到:

privatestaticclassIntegerCache{

staticfinalint low = -128;

staticfinalint high;

staticfinalInteger cache[];

static{

// high value may be configured by property

int h = 127;

String integerCacheHighPropValue =

sun.misc.VM.getSavedProperty("java.lang.Integer.IntegerCache.high");

// 省略其它代码

}

// 省略其它代码

}

从这我们也可以看出问题2的答案,为什么很多规范都推荐构建实例的时候是Integer a = 5;的形式,而不是new Integer(5);的原因,可以减少实例的创建,复用缓存对象。接着我们再来看第一个问题,==比较和equals比较的区别在哪?我们知道==比较的是两个实例对象的内存地址,而equals则是比较的具体的实现,而基本类型的包装类实现实例如果不在缓存范围内,肯定不是同一个对象,逻辑上内存地址肯定是不一样的,所以==在超过缓存范围后,比较的结果并不准确,那么我们该如何比较呢?事实上,基本类型的包装类中都有获取具体value的方法,例如Integer中就有intValue的方法,获取具体的值,类型为基本类型,这样我们再去==比较就可以了,那么equlas方法为什么可以比较呢?我们就拿Long类型的equals方法的源码来看一下具体实现:

public boolean equals(Object obj) {

if (obj instanceof Long) {

return value == ((Long)obj).longValue();

}

return false;

}

可以看到这类包装类型的比较其实也就是我们上述说的获取具体value值以后再去==比较的操作。

空指针

空指针基本是每个Java开发人员最恶心的异常也是见过最多的异常之一,可能出现在各种业务代码和场景中,在阿里规范手册中,有很多针对空指针的规范和处理,如下:

【强制】Object 的 equals 方法容易抛空指针异常,应使用常量或确定有值的对象来调用 equals。【推荐】防止 NPE,是程序员的基本修养,注意 NPE 产生的场景:

  1. 返回类型为基本数据类型,return 包装数据类型的对象时,自动拆箱有可能产生 NPE。反例:public int f () { return Integer 对象}, 如果为 null,自动解箱抛 NPE。

  2. 数据库的查询结果可能为 null。

  3. 集合里的元素即使 isNotEmpty,取出的数据元素也可能为 null。

  4. 远程调用返回对象时,一律要求进行空指针判断,防止 NPE。

  5. 对于 Session 中获取的数据,建议进行 NPE 检查,避免空指针。

  6. 级联调用 obj.getA ().getB ().getC (); 一连串调用,易产生 NPE。

可见空指针出现的场景可能会有很多,而在开发中一些必要的检查,减少空指针是每个程序员都应该有的素质,但是有些不规范的操作或者疏忽可能会导致空指针的诞生,例如:

1.服务交互信息不规范的坑:一个经典的接口服务交互的场景下,往往有时候会将服务中的异常进行try-catch处理,返回的是一个固定的result封装实例,这种情况下,如果内部属性设置不规范很容易在调用方使用返回实例进行操作的时候因为疏忽导致空指针异常。

2.返回实例的坑:还有一些服务的代码编写过程中,部分开发人员有自己的个性写法,例如数据库查询某个数据的时候,如果查询不出结果集,并不是返回null,而是创建一个空的实例,进行返回,这一下可好,调用方无论怎么校验空指针都会在使用getxxx方法获取到的属性进行操作的时候报空指针异常,除非调用方将内部所有的get返回的结果都去进行一次空指针判断,或者根据某几个唯一属性确认实例是否为空等,但无论如何操作,都无法避免可能存在的大量的空指针。

3.自动拆箱装箱的坑:在企业开发的过程中,往往存在大量的实例转换操作,这个时候我们往往是通过工具类进行转换,但是有时候我们的实例是存在于两个工程内的,往往有时候因为是两个人定义的,同样名称的类变量,但是类型一个是基础类型,一个是包装类型,这个时候往往我们下意识会觉得java会自动拆箱装箱,所以没关系的,肯定会转换过去的,再或者基本类型有默认值的,肯定不会出现空指针,想法很美好,但是事实真的如此吗?我们看一个例子:

@Data

public class GoodCreateDTO {

private String title;

private Long price;

private Long count;

}

@Data

public class GoodCreateParam implements Serializable {

private static final long serialVersionUID = -560222124628416274L;

private String title;

private long price;

private long count;

}

这个时候我们潜意识中会认为外部接口的变量都是包装类型或者引用类型,所以我们在实现了类似如下的转换代码的时候就容易出现空指针操作:

public class GoodCreateConverter {

public static GoodCreateParam convertToParam(GoodCreateDTO goodCreateDTO) {

if (goodCreateDTO == null) {

return null;

}

GoodCreateParam goodCreateParam = new GoodCreateParam();

//赋值操作

goodCreateParam.setTitle(goodCreateDTO.getTitle());

goodCreateParam.setPrice(goodCreateDTO.getPrice());

goodCreateParam.setCount(goodCreateDTO.getCount());

return goodCreateParam;

}

}

但是如果在传递来的实例中,count不是必传参数,可能存在null的时候,这个时候我们使用getCount操作,由于获取的类型是包装类型,而我们需要赋值的是基本类型,这个时候就会触发自动拆箱装箱,null的拆箱就会报空指针异常!

c44dd1fbd56eb71b2222320736ff77b5.png

往期精选

CHOICENESS

432640840bab217a39bbf695b5f08cf5.png

5b3d6dcf2c64a56c8e27087f44369a6d.png

eb36816de559444bc865e0cdba1da83a.png

33d66268ca86f1b10fe7cef9dc400151.png是兄弟,就来“kan”1e32845f7726f75614569043ed2a68a5.gif

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/410442.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Charles

安装 https://www.jianshu.com/p/cb744a4c0344 https://blog.csdn.net/qq_28831197/article/details/81196571 使用说明&#xff1a; 来源&#xff1a;https://www.jianshu.com/p/73b134559c76 过滤网络请求 通常情况下&#xff0c;我们需要对网络请求进行过滤&#xff0c;只监…

.NET Core Docker使用初入篇

本篇内容如何在CentOS上安装Docker服务器与工具准备安装Docker更新系统安装Docker源设置Docker开机启动启动Docker使用Docker运行一个.NET Core 例子.net core 例子拉取.net core 例子停止.net core 例子启用其他如何在CentOS上安装Docker 服务器与工具准备 首先我们需要一个…

如何延长作用域链_第4部分2:作用域(链)和 闭包

知识列表作用域/作用域链 闭包&#xff08;涉及JS垃圾回收机制 &#xff09;https://zhuanlan.zhihu.com/p/27110726 【 js 基础 】【读书笔记】作用域和闭包https://juejin.im/post/5afb0ae56fb9a07aa2138425 深入理解闭包之前置知识→作用域与词法作用域&#xff08;一&#…

C# T4模板在项目中的使用

1.什么是t4模版 T4&#xff0c;即4个T开头的英文字母组合&#xff1a;Text Template Transformation Toolkit。 T4(Text Template Transformation Toolkit)是微软官方在VisualStudio 2008中开始使用的代码生成引擎。在 Visual Studio 中&#xff0c;“T4 文本模板”是由一些文…

Docker中安装Jenkins实时发布.net core 项目(一)

Docker中安装Jenkins实时发布.net core 项目安装docker懒人篇手动安装dockerfile安装jenkins常规安装jenkinsjenkins的安装搜索jenkins拉取jenkins容器jenkins的启动jenkins密码其他安装docker 使用curl安装最新版 curl -fsSL https://get.docker.com/ | sh重启Docker systemc…

Docker中安装Jenkins实时发布.net core 项目(二)

Docker中安装Jenkins实时发布.net core 项目防坑点升级dockerjenkins运行运行命令jenkins拉取git并构建项目其他查看发布文件防坑点 升级docker 首先我们要确认我们在liunx安装的不是1.31.1的docker容器不然在后面的运行中会报错 can not open /etc/sysconfig/docker如果你是…

Jenkins构建 netcore5.0 项目时出现NU3028/NU3037错误的解决方案

我在使用Jenkins自动化部署项目的时候&#xff0c;出现了如下的错误 error NU3028: Package System.IO.Compression 4.3.0 from source https://api.nuget.org/v3/index.json: The repository primary signatures timestamp found a chain building issue: UntrustedRoot: self…

2019长安大学ACM校赛网络同步赛 L XOR

题意 求区间内有多少数x满足x^4x^5x0 1≤l≤r≤1018. 题解 根据异或的性质可以推到 x^4x5x -->x^4xx4x 即x和4x每一位都不同&#xff0c;即x和(x<<2)每一位都不同&#xff0c;就是x中每一位都与他前前一位不同。 那么就很简单了&#xff0c;可以很容易写出数位DP状态f…

贝塞尔曲线 总结

Bzier curve(贝塞尔曲线)是应用于二维图形应用程序的数学曲线。 曲线定义&#xff1a;起始点、终止点&#xff08;也称锚点&#xff09;、控制点。通过调整控制点&#xff0c;贝塞尔曲线的形状会发生变化。 1962年&#xff0c;法国数学家Pierre Bzier第一个研究了这种矢量绘制曲…

python变量标识符_简谈-Python的注释、变量类型、标识符及关键字

在Python程序中&#xff0c;要想支持中文输出&#xff0c;则要在代码前面添加标识符&#xff1a;开发人员在程序中自定义的一些符号和名称 标示符是自己定义的,如变量名 、函数名等 标识符的规则&#xff1a; 标示符由字目、下划线和数字组成&#xff0c;且数字不能开头 python…

win10使用docker desktop安装k8s一直starting解决方法

在docker中启动k8s一直卡在staring当中查了许多文档都写得不明不白的&#xff0c;研究了许久终于解决决定写个帖子来记录一下 1.首先查看本地docker中k8s的版本拉取源码 我们这里是1.19.7 然后我们进入到 k8s下载 去拉取k8s源码 git clone https://codechina.csdn.net/mirr…

Android菜单详解(三)——SubMenu和IconMenu

我们在上一篇介绍了如何在Android中创建和响应选项菜单&#xff0c;今天我们将探索子菜单和图标菜单。 子菜单Sub Menu 子菜单提供了一种自然的组织菜单项的方式&#xff0c;它被大量地运用在windows和其他OS的GUI设计中。Android同样支持子菜单&#xff0c;你可以通过addSubMe…

Liunx下使用Nginx负载均衡

我是centos8得主机 安装命令: yum install nginx 如果为Ubuntu主机 sudo apt-get install nginx 安装完成后&#xff0c;启用并启动Nginx服务&#xff1a; sudo systemctl enable nginxsudo systemctl start nginx 然后我们有2个服务&#xff1a; 一个地址为: http://xx…

如何给微软提反馈建议以及bug

1.相信各位在使用.net core的过程中多多少少遇到了bug和为解决的坑那么我们肿么联系微软反馈问题你 1.找到vs编辑器中的反馈按钮 2.点击进入网址 如果是vs的问题选择visual studio栏目,如果为编译问题或者其他问题请选择对应的栏目 然后写下你的问题和截图&#xff0c;尽量详…

windwos docker安装k8s一直staring的解决方法

今天遇到了一个很奇怪的问题 docker中启动k8s一直卡在starting 然后就不动了&#xff0c;找了很多解决方法终于得到解决这里把解决流程写在这里 1.配置镜像加速器 首先登录阿里云&#xff0c;阿里云有一个免费的镜像加速服务&#xff0c;可以加快拉取docker容器的速度这里一定…

对未标记为可安全执行的脚本_三、??XSS跨站脚本攻击

跨站脚本攻击(Cross Site Scripting)&#xff0c;缩写为XSS。恶意攻击者往Web页面里插入恶意Script代码&#xff0c;当用户浏览该页之时&#xff0c;嵌入其中Web里面的Script代码会被执行&#xff0c;从而达到恶意攻击用户的目的。理论上&#xff0c;所有可输入的地方没有对输入…

.net 使用阿里云RocketMQ

1.首先我们来讲解一下消息队列的作用 比如说我们的订单系统&#xff0c;再客户订单生成了以后&#xff0c;可能会有 快递系统&#xff0c;通知系统&#xff0c;和打印系统需要用到当前订单的详细内容 所以这个时候常规的操作是在A里面通过代码调用B&#xff0c;C &#xff…

tensorflow 目标分割_Tensorflow中的控制流和优化器

控制流只要对tensorflow有一点了解&#xff0c;都应该知道graph是tensorflow最基本的一个结构。Tensorflow的所有计算都是以图作为依据的。图的nodes表示一些基本的数学运算&#xff0c;比如加法&#xff0c;卷积&#xff0c;pool等。Node使用protoBuf来进行描述&#xff0c;包…

Reflector 已经out了,试试ILSpy

Reflector是.NET开发中必备的反编译工具。即使没有用在反编译领域&#xff0c;也常常用它来检查程序集的命名规范&#xff0c;命名空间是否合理&#xff0c;组织类型的方法是否需要改善。举例说明&#xff0c;它有一个可以查看程序集完整名称的功能&#xff0c;请看下图 这里的…

Go语言通过odbc驱动连接华为高斯数据库

1.下载odbc驱动 下载后安装psqlodbc_x64.msi 安装成功后可在odbc数据源中看到以下内容 2.测试odbc驱动 在用户dsn中选择添加 输入对应的连接内容点击test 如果显示以下内容则表示驱动正常可使用odbc连接高斯数据库 3.go 语言编写 其中依赖包需要使用命令安装 go get github.c…