java 实现按规则自增功能_第一章 Java开发中通用的方法和准则

不要在常量和变量中出现易混淆的字母

包名全小写,类名首字母全大写,常量全部大写并用下划线分割,变量采用驼峰(Camel Case)命名。在变量的声明中不要引入容易混淆的字母:

long i=1l;

System.out.println("i的两倍是:"+(i+i));

如果字母和数字混合使用,字母“l”务必大写,字母“O”则增加注释。

注意,字母“l”作为长整型标志时务必大写。

莫让常量蜕变成变量

加了final和static的常量可能会变吗?

interface ConstDemo {

public static final int RAND_CONST = new Random().nextInt();

}

System.out.println("常量会变哦:" + ConstDemo.RAND_CONST);

常量就是常量,在编译器就必须确定其值,不应该在运行期更改,负责程序的可读性会非常差,甚至连作者自己都不能确定在运行 期发生了何种神奇的事情。

三元操作符的类型务必一致

int i = 80;

String s = String.valueOf(i < 100 ? 90 : 100);

String s1 = String.valueOf(i < 100 ? 90 : 100.0);

System.out.println("两者是否相等:" + s.equals(s1));

三元操作符类型的转换规则:

若两个操作数不可转换,则不做钻换,返回值为Object类型

若干两个操作数是明确类型额表达式(比如变量),则按正常的二进制数字来转换,int类型转换为long类型,long类型转换为float类型等。

若两个操作数中有一个是数字S,另外一个是表达式,且其类型标识为T,那么,若数字S在T的范围内,则转换为T类型;若S超出T类型的范围,则T转换为S类型

若两个操作数都是直接量数字,则返回值类型为范围较大者。

注意保证三元操作符中两个操作数类型一致,即可减少错误的发生。

避免带有变长参数的方法重载

public void calPrice(int price, int discount) {

float knockdownPrice = price * discount / 100.0F;

System.out.println("简单折扣后的价格是:" + formateCurrency(knockdownPrice));

}

public void calPrice(int price, int... discounts) {

float knockdownPrice = price;

for (int discount : discounts) {

knockdownPrice = knockdownPrice * discount / 100;

}

System.out.println("复杂折扣后的价格是:" + formateCurrency(knockdownPrice));

}

private String formateCurrency(float price) {

return NumberFormat.getCurrencyInstance().format(price / 100);

}

Java在编译时,首先会根据实参的数量和类型来进行处理,也就是查到calPrice(int price,int discount)方法,而且确认它是否符合方法签名条件。

int是一个原生数据类型,而数组本身是一个对象,编译器想要“偷懒”,所以会这样选择。

慎用变长参数的方法重载,让人伤脑经不说,苏红补丁哪天就陷入这类小陷阱里了。

别让null值和空值威胁到变长方法

public class Client {

public void methodA(String str, Integer... is) {

}

public void methodA(String str, String... strs) {

}

public static void main(String[] args) {

Client client = new Client();

client.methodA("China", 0);

client.methodA("China", "People");

client.methodA("China", null);

}

}

public static void main(String[] args){

Client client = new Client();

String[] strs = null;

client.methodA("China",strs);

}

让编译器知道这个null值是String类型的,编译即可顺利通过,也就减少了错误的发生。

覆写变长方法也循规蹈矩

在Java中,子类覆写符类的方法很常见,这样做既可以修正Bug也可以提供扩展的业务功能支持,同时还符合开闭原则(Open-Closed Principle)。覆写必须满足的条件:

重写方法不能缩小访问权限。

参数列表必须与被重写方法相同。

返回类型必须与重写方法的相同或者是其子类。

重写方法不能抛出新的异常,或者超出符类范围的异常,但是可以抛出更少,更有限的异常,或者不抛出异常。

public class Client {

public static void main(String[] args) {

Base base = new Sub();

base.fun(100, 50);

Sub sub = new Sub();

sub.fun(100, 50);

}

}

class Base {

void fun(int price, int... discounts) {

System.out.println("Base.....fun");

}

}

class Sub extends Base {

@Override

void fun(int price, int[] discounts) {

System.out.println("Sub.....fun");

}

}

警惕自增的陷阱

int count = 0;

for (int i = 0; i < 10; i++) {

count = count++;

}

System.out.println("count=" + count);

结果是0

count++是一个表达式,是由返回值的,它的返回值就是count自加前的值,Java对自加是这样处理的:首先把count的值(注意是值,不是引用)拷贝到一个临时变量区,然后对count变量加1,最后返回临时变量区的值。程序第一次玄幻时的详细处理步骤如下:

1.JVM把count的值(其值是0)拷贝到临时变量区

2.count值加1,这时候count的值是1

3.返回临时变量区的值,注意这个值是0,没修改过。

4.返回值赋值给count,此时count值被重置成0.

不要让旧语法困扰你

Java中没有了goto关键字,但是扩展了break和continue关键字。

少用静态导入

静态导入语法(import static)其目的是为了减少字符串输入量,提高代码的可阅读性,以便更好的理解程序。但是,滥用静态导入回是程序更难于都,更难维护。会让阅读者很难弄清除其属性或方法代表何意,甚至是哪一个类的属性(方法)都要思考一番。(IDE友好提示是另说)

对于静态导入,一定要遵循两个原则:

1.不使用*(星号)通配符,除非是导入静态常量类(只包含常量的类或接口)。

2.方法名是具有明确,清晰表象意义的工具类

不要在本类中覆盖静态导入的变量和方法

编译器有一个“最短路径”原则:如果能在奔雷中找到的变量,常量,方法,就不会到其他包或者符类,接口中查找,以确保奔雷中的属性,方法优先。

如果要变更一个被导入的方法,最好的办法是在原始类中重构,而不是在本类中覆盖。

养成良好习惯,显式声明UID

类实现Serializable接口目的是为了可持久化,比如网络传输或本地存储,为系统的分布和异构部署提供先决支持条件。若没有序列化,现在我们熟悉的远程调用,对象数据库都不可能存在。

通过SerialVersionUID,也叫做流标识符,即类的版本定义的,它可以显式声明也可以隐式声明。显式声明格式如下:

private static final long serialVersionUID = XXXXXL;

而隐式声明是我不声明,你编译器在编译的时候帮我生成。

JVM在反序列化时,会比较数据流中的serialVersionUID与类的serialVersionUID是否相同,如果相同,则认为类没有发生改变;如果不相同,JVM不干了,抛个异常InvalidClassException。

显式声明serialVersionUID可以提高代码的健壮性。

~~## 避免用序列化类在构造函数中为不变量赋值

避免为final变量复杂赋值

使用序列化类的私有方法巧妙解决部分属性持久化问题~~

break万万不可忘

case后缺少break往往会称为bug所在。

可以再IDE中做相应的设置,将switch语句中,每个case不以break结尾的情况设置为编译错误。

易变业务使用脚本语言编写

例如我们项目中的公式。

慎用动态编译

动态编译一致是java的梦想,从Java6版本它开始支持动态编译了,可以在运行期直接编译.java文件,执行.class,并且能够获得相关的输入输出,甚至还能监听相关的事件。

使用动态编译时需要注意以下几点:

1.在框架中谨慎使用

2.不要再要求高性能的项目使用

3.动态编译要考虑安全性问题

4.记录动态编译过程。(空中编译和运行是很让人不放心的,留下些一句可以更好地优化程序)

避免instanceof非预期结果

public class Client {

public static void main(String[] args) {

//String对象是否是Object的实例

boolean b1 = "Sting" instanceof Object;

//String对象是否是String的实例

boolean b2 = new String() instanceof String;

//Object对象是否是String的实例

boolean b3 = new Object() instanceof String;

//拆箱类型是否是装箱类型的实例

boolean b4 = 'A' instanceof Character;

//空对象是否是String的实例

boolean b5 = null instanceof String;

// 类型转换后的空对象是否是String的实例

boolean b6 = (String) null instanceof String;

// Date对象是否是String的实例

boolean b7 = new Date() instanceof String;

// 在泛型类中判断String对象是否是Date的实例

boolean b8 = new GenericClass().isDateInstance("");

}

}

class GenericClass {

//判断是否是Date类型

public boolean isDateInstance(T t) {

return t instanceof Date;

}

}

'A' instanceof String无法编译通过,因为'A'是一个char类型,也就是一个基本类型,不是一个对象,instanceof只能用于对象的判断,不能用于基本类型的判断。

不要只替换一个类

对于final修饰的基本类型和String类型,编译器会认为它是稳定态(Immutable Status),所以在编译时就直接把值变异到字节码中了,编码了在运行期引用,以提高代码的执行效率。

对于final修饰的类(即非基本类型,编译器认为它是不稳定态(Mutable Status)),在编译时简历的则是引用关系,如果Client类引入的常量是一个类或实例,即使不重新编译也会输出最新值。

注意:发布应用系统时禁止使用类文件替换方式,整个WAR包或者JAR包发布才是万全之策。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值