浅谈Java开发规范与开发细节(上)

  1. 使代码审核变得更有效率,专注于更重要的问题,而不是争论语法和命名规范这类小细节,提高开发效率;
  2. 提高代码的清晰度、可读性以及美观程度;
  3. 避免不同产品之间的命名冲突。

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

驼峰命名法

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

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

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

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

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

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

例如下面的转换案例:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

蛇形命名法

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

串式命名法

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

匈牙利命名法

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

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

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

总结下来,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,抛异常
}
//后续一堆业务代码
}

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

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

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

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源码中看到:

private static class IntegerCache {
static final int low = -128;
static final int high;
static final Integer cache[];
static {
// high value may be configured by property
int h = 127;
String integerCacheHighPropValue =
sun.misc.VM.getSavedProperty(“java.lang.Integer.IntegerCache.high”);
// 省略其它代码
}
自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数Java工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年Java开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Java开发知识点,真正体系化!

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!

如果你觉得这些内容对你有帮助,可以扫码获取!!(备注Java获取)

img

总结

上述知识点,囊括了目前互联网企业的主流应用技术以及能让你成为“香饽饽”的高级架构知识,每个笔记里面几乎都带有实战内容。

很多人担心学了容易忘,这里教你一个方法,那就是重复学习。

打个比方,假如你正在学习 spring 注解,突然发现了一个注解@Aspect,不知道干什么用的,你可能会去查看源码或者通过博客学习,花了半小时终于弄懂了,下次又看到@Aspect 了,你有点郁闷了,上次好像在哪哪哪学习,你快速打开网页花了五分钟又学会了。

从半小时和五分钟的对比中可以发现多学一次就离真正掌握知识又近了一步。

人的本性就是容易遗忘,只有不断加深印象、重复学习才能真正掌握,所以很多书我都是推荐大家多看几遍。哪有那么多天才,他只是比你多看了几遍书。

《互联网大厂面试真题解析、进阶开发核心学习笔记、全套讲解视频、实战项目源码讲义》点击传送门即可获取!

[外链图片转存中…(img-66d65stP-1713743361344)]

人的本性就是容易遗忘,只有不断加深印象、重复学习才能真正掌握,所以很多书我都是推荐大家多看几遍。哪有那么多天才,他只是比你多看了几遍书。

《互联网大厂面试真题解析、进阶开发核心学习笔记、全套讲解视频、实战项目源码讲义》点击传送门即可获取!

  • 9
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值