文档章节

[笔记]改善Java程序的151个建议---第一章 Java开发中通用的方法和准则

jimyao
 jimyao
发布于 2016/01/29 14:45
字数 1975
阅读 10
收藏 0

第一章 Java开发中通用的方法和准则

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

字母“l”务必大写,字母“o”增加注释


建议2:莫让常量蜕变成变量

常量就是常量,在编译期必须确定其值,不应该在运行期更改,否则程序在运行期发生各种事情。

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


建议3:三元操作符的类型务必一致

类型不一致如:i < 100 : 90: 100.0(float)


建议4:避免带有变长参数的方法重载

变长参数,必须是方法的最后一个参数,一个方法不能定义多个变长参数。

避免变长参数重载,如下:

public void calPrice(int price, int discount)

public void calPrice(int price, int... discount)


建议5: 别让null值和空值威胁到变长方法

如:

public void method(String str, Integer... is)

public void method(String str, String... is)

client.method("China");

client.method("China", null);


正确做法:

String strs = null;

client.method("China", strs);


建议6:覆写变长方法也要遵循规矩

@Override必须满足如下条件:

从写方法不能缩小访问权限;

参数列表必须与被重写方法相同;(参数数量相同,类型相同,顺序相同)

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

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


建议7:警惕自增的陷阱

错误语句,如:

int count = 0;

count= count++;  //结果是count的初始值0


建议8:不要让旧语法困扰你

goto语句

break,continue后面可以加上冒号做跳转,实现goto功能。


建议9:少用静态导入

如: import static java.lang.Math.PI


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

//常量名誉静态导入的PI相同

public final static String PI="祖冲之";


建议11:养成良好习惯,显式声明UID

序列化标志接口

Serial Version ID流标识符(类的版本定义),如果没有的话,序列化和反序列化所对应的类版本发生了变化,JVM不能把数据流转换为实例对象。

private static final long serialVersionUID = *****L;

隐式声明会根据类的各种属性,方法,关系,类名,包名,参数,返回值等计算得出。


建议12:避免用序列化类在构造函数中卫不变量赋值(final)

static序列化时候根本没有保存到数据流中

下面错误,如:

public class Person implements Serializable{

     public final String name;

     Person(){

          name = "aa";

     }

}


建议13:避免为final变量复杂赋值

final变量赋值还有一种方式,通过方法赋值。

public final String  name = initName();


final会被重新赋值,是指简单对象,8个基本类型,数组,字符串(不通过new生成的String),但是不能方法赋值。


保存到磁盘(网络传输)上的对象文件包括2个部分:

类描述信息:包路径,继承关系,访问权限,变量描述,变量访问权限,方法签名,返回值,变量关联类信息。不记录方法,构造函数,static等。

transient,static的实例变量值

关联类也必须序列化


总结,反序列化时候final变量在以下情况下不会被重新赋值。

通过构造函数为final变量赋值

通过方法返回值为final变量赋值

final修饰的属性不是基本类型


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

部分属性持久化,把不需要持久化的属性前面加上transient


姓名,基本工资可以序列化

绩效工资保密,不能序列化


实现了Serializable接口的类可以实现两个私有方法:writeObject和readObject。用来影响和控制序列化和反序列化的过程。

序列化的独有机制:序列化回调。Java调用ObjectOutputStream类把一个对象转换成流数据的时候,会通过反射检查被序列化的类是否有writeObject方法,并且检查其是否符合私有、无返回值的特征。如果有,则会委托该方法进行对象序列化。如没有,则由ObjectOutputStream按照默认规则继续序列化。readObject也一样。


import java.io.Serializable;



public class Salary implements Serializable {


        private static final long serialVersionUID = -5402065593284392992L;

        //基本工资

        private int basePay ;

        //绩效工资

        private int bonus ;

       

       Salary( int basePay , int bonus){

               this.basePay = basePay ;

               this.bonus = bonus ;

       }

       

        public int getBasePay() {

               return basePay ;

       }

       

        public void setBasePay(int basePay) {

               this.basePay = basePay ;

       }

       

        public int getBonus() {

               return bonus ;

       }

       

        public void setBonus(int bonus) {

               this.bonus = bonus ;

       }

       

       

}


import java.io.IOException;

import java.io.ObjectInputStream;

import java.io.ObjectOutputStream;

import java.io.Serializable;



public class Person implements Serializable{


        /**

        * Person serialVersionUID

        */

        private static final long serialVersionUID = 7592930394427200495L;

        //姓名

        private String name ;

        //薪水

        private transient Salary salary ;

       

       Person(String name, Salary salary){

               this.name = name ;

               this.salary = salary ;

       }


        public String getName() {

               return name ;

       }


        public void setName(String name) {

               this.name = name ;

       }


        public Salary getSalary() {

               return salary ;

       }


        public void setSalary(Salary salary) {

               this.salary = salary ;

       }

       

        //序列化委托方法

        private void writeObject(ObjectOutputStream out) throws IOException{

               out.defaultWriteObject();

               out.writeInt( this.salary .getBasePay());

       }

       

        //反序列化委托方法

        private void readObject(ObjectInputStream in) throws ClassNotFoundException, IOException{

               in.defaultReadObject();

               this.salary = new Salary(in.readInt(), 0);

       }

}


import java.io.FileInputStream;

import java.io.FileNotFoundException;

import java.io.FileOutputStream;

import java.io.IOException;

import java.io.ObjectInputStream;

import java.io.ObjectOutputStream;

import java.io.Serializable;



public class SerializationUtils {

        private static String FILE_NAME = "d:/a.bin";

        //序列化

        public static void writeObject(Serializable s) {

              ObjectOutputStream oos;

               try {

                      oos = new ObjectOutputStream(new FileOutputStream(FILE_NAME ));

                      oos.writeObject( s);

                      oos.close();

              } catch (FileNotFoundException e ) {

                      // TODO Auto-generated catch block

                      e.printStackTrace();

              } catch (IOException e ) {

                      // TODO Auto-generated catch block

                      e.printStackTrace();

              }


       }

       

        public static Object readObject(){

              Object obj = null;

               //反序列化

               try {

                     

                     ObjectInputStream input = new ObjectInputStream(new FileInputStream(FILE_NAME ));

                      obj = input.readObject();

                      input.close();

              } catch (IOException | ClassNotFoundException e ) {

                      // TODO Auto-generated catch block

                      e.printStackTrace();

              }

               return obj ;          

       }

}


//序列化Client

public class SerializeClient {


        public static void main(String[] args) {

               //基本工资1000,绩效工资25000

              Salary salary = new Salary(1000, 25000);

               //记录人员信息

              Person person = new Person("张三" , salary );

              SerializationUtils. writeObject(person);

       }


}


//反序列化

public class DeSerializationClient {


        public static void main(String[] args) {

               //反序列化并打印信息

              Person p = (Person)SerializationUtils. readObject();

              StringBuffer sb = new StringBuffer();

               sb.append( "姓名 : " + p .getName());

               sb.append( "\t基本工资: " + p .getSalary().getBasePay());

               sb.append( "\t绩效工资: " + p .getSalary().getBonus());

              System. out.println(sb );

       }

}


建议15:break万万不可忘
switch... case...
Performaces->Java->Compiler->Errors/Warnings->Potential Programming problems->'switch' case fall-through->Errors

建议16:易变业务使用脚本语言编写
脚步语言:灵活,便捷,简单。如Groovy

建议17:慎用动态编译

建议18:避免instanceof非预期结果
判断一个对象是否是一个类的实例

建议19:断言不是鸡肋
防御式编程中经常用断言Assertion对参数和环境做出判断,避免程序因不当的输入或错误的环境产生逻辑异常。断言是为调试程序而用。
assert默认是不启用的;assert抛出的异常AssertionErro是继承自Error。
防御式编程特点,所有外部因素都是邪恶的,存在企图摧毁程序的罪恶本源。为了抵制,要在程序中处处检验,设卡,不满足条件就不再执行后面的程序。保护主程序的正确性。
不能用断言在公开方法中做输入校验。
不能用断言在布尔表达式中执行逻辑代码

正确使用断言:按照正常执行逻辑不可能达到的代码区域放置断言
(1)私有方法中放置断言,作为输入参数的校验
(2)流程控制中不可能达到的区域,意义:程序执行到这里就是错误的。
(3)建立程序探针,断言变量之间的关系

建议20:不要只替换一个类
一个常量接口(类),编译器认为它是稳定态,所以编译时候直接把值编译到字节码中。以后无论怎么修改这个常量接口(类)里面的值,只要不重新编译,输出的还是原来的值。
发布应用系统时候,禁止使用类文件替换方式,整体WAR包发布是完全之策。
public class Constant{
     public final static int MAX_AGE = 100;
}


© 著作权归作者所有

共有 人打赏支持
jimyao
粉丝 17
博文 66
码字总数 27856
作品 0
朝阳
云栖社区专家系列课——Java必修课第一讲

本节课为 Java必修课第一讲。在本节课中,最课程创始人、微软MVP陆敏枝为了大家介绍了当前Java行业的IT人才供需情况、Java基本语法、JDK的下载与安装、Java环境变量的配置以及第一个Java程序...

笑傲江湖lcx
07/03
0
0
Android--面试中遇到的问题总结(三)

《Android 开发工程师面试指南 LearningNotes 》,作者是陶程,由梁观全贡献部分。大家可以去知乎关注这两位用心的少年。这份指南包含了大部分Android开发的基础、进阶知识,不仅可以帮助准备...

sealin
2017/02/22
0
0
《编写高质量代码 改善Java程序的151个建议》读书笔记

第7章 泛型和反射 建议94 不能初始化泛型参数的数组 Java的泛型在编译期有效,在运行期被删除,所有的泛型参数类型在编译后都会被擦出掉 Java泛型类和普通类在编译后都指向同一字节码 第8...

OSC_fly
08/23
0
0
新手入门必看的30个问题!!!!!!

看了好多资料,还是对一些基本问题比较头大。在论坛看完这个帖子,脑子里的基本概念有了。 1 什么是Java、Java2、JDK?JDK后面的1.3、1.4.2版本号又是怎么回事? 答:Java是一种通用的,并发的,...

精华之王
2009/04/11
0
0
Java map双括号初始化方式的问题

关于Java双括号的初始化凡是确实很方便,特别是在常量文件中,无可替代。如下所示: Map map = new HashMap() {   {   put("Name", "Unmi");   put("QQ", "1125535");   } }; 好处很明...

Airship
2015/02/28
0
0

没有更多内容

加载失败,请刷新页面

加载更多

20180920 rzsz传输文件、用户和用户组相关配置文件与管理

利用rz、sz实现Linux与Windows互传文件 [root@centos01 ~]# yum install -y lrzsz # 安装工具sz test.txt # 弹出对话框,传递到选择的路径下rz # 回车后,会从对话框中选择对应的文件传递...

野雪球
今天
2
0
OSChina 周四乱弹 —— 毒蛇当辣条

Osc乱弹歌单(2018)请戳(这里) 【今日歌曲】 @ 达尔文:分享花澤香菜/前野智昭/小野大輔/井上喜久子的单曲《ミッション! 健?康?第?イチ》 《ミッション! 健?康?第?イチ》- 花澤香菜/前野智...

小小编辑
今天
8
3
java -jar运行内存设置

java -Xms64m #JVM启动时的初始堆大小 -Xmx128m #最大堆大小 -Xmn64m #年轻代的大小,其余的空间是老年代 -XX:MaxMetaspaceSize=128m # -XX:CompressedClassSpaceSize=6...

李玉长
今天
4
0
Spring | 手把手教你SSM最优雅的整合方式

HEY 本节主要内容为:基于Spring从0到1搭建一个web工程,适合初学者,Java初级开发者。欢迎与我交流。 MODULE 新建一个Maven工程。 不论你是什么工具,选这个就可以了,然后next,直至finis...

冯文议
今天
2
0
RxJS的另外四种实现方式(四)——性能最高的库(续)

接上一篇RxJS的另外四种实现方式(三)——性能最高的库 上一篇文章我展示了这个最高性能库的实现方法。下面我介绍一下这个性能提升的秘密。 首先,为了弄清楚Most库究竟为何如此快,我必须借...

一个灰
今天
3
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部