知识屋:更实用的电脑技术知识网站
所在位置:首页 > 科技

改善java程序的151个建议

发表时间:2022-03-24来源:网络

《编写高质量代码-改善java程序的151个建议》php

--秦小波html

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

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

long a=0l; --> long a=0L;

二、莫让常量蜕变成变量c++

static final int t=new Random().nextInt();

三、三元操做符的类型无比一致web

int i=80; String s=String.valueOf(i 也是;List则表示集合中的全部元素

2)List能够进行读写操做,它的类型是固定的T类型,在编码期不须要进行任何的转型操做;List 是只读类型的,由于编译器不知道list中容纳的是什么类型的元素,并且读出来的元素都是object类型的,须要主动转型,因此它常常用于泛型方法的返回值。注意list能够remove,clear等,由于删除动做与泛型类型无关 ; List也能够读写操做,可是它执行写入操做时须要转型,而此时已经失去了泛型存在的意义了

9九、严格限定泛型类型采用多重界限

 举个例子

100、数组的真实类型必须是泛型类型的子类型

10一、注意Class类的特殊性

java语言是先把java源文件编译成后缀为class的字节码文件,而后再经过classloader机制把这些类文件加载到内存中,最后生成实例执行的。java使用一个元类MetaClass来描述加载到内存中的类数据,这就是Class类,它是一个描述类的类对象。特殊性:

1)无构造函数。Class对象是在加载类时由java虚拟机经过调用类加载器中的defineClas方法自动构造的

2)能够描述基本类型。虽然8个基本类型在jvm中并非一个对象,它们通常存在于栈内,可是class类仍然能够描述它们,int.class

3)其对象都是单例模式。一个Class的实例对象描述一个类,而且只描述一个类。

Class类是java的反射入口,只有在得到类一个类的描述对象后才能动态地加载,调用。通常得到一个class对象有三种途径

1) 类属性方式 String.class

2) 对象的getClass方法 new String().getClass()

3) forName方法加载 Class.forName("java.lang.String")

10二、实时选择getDeclaredMethod和getMethod

getMethod:得到全部public访问级别的方法,包括从父类继承的方法

getDeclaredMethod:得到自身类的全部方法,包括public、private等

10三、反射访问属性或者方法时将accessible设置为true

accessible属性表示是否容易得到,是否须要进行安全检查。咱们知道,动态修改一个类或方法都会受java安全体系的制约,而安全的处理是很是消耗资源的(性能很是低),所以对于运行期要执行的方法或属性就提供类accessible可选项:由开发者决定是否要逃避安全体系的检查

invoke的执行:

@CallerSensitive public Object invoke(Object obj, Object... args) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException { if (!override) {//保存了accessible的值 if (!Reflection.s(clazz, modifiers)) { Class caller = Reflection.getCallerClass(); checkAccess(caller, clazz, obj, modifiers); } } MethodAccessor ma = methodAccessor; // read volatile if (ma == null) { ma = ac(); } return ma.invoke(obj, args); }

accessible属性只是用来判断是否须要进行安全检查的,若是不须要则直接执行,这就能够大幅度地提高系统性能(因为取消了安全检查,也能够运行private方法,访问private属性)。通过大量测试,在大量的反射状况下,设置accessible为true能够提高性能20倍以上

10四、使用forName动态加载类文件

10五、动态加载不适合数组

数组是一个很是特殊的类,虽然它是一个类,但没有定义类路径。编译后会为不一样的数组类型生成不一样的类

因此其实是能够动态加载一个对象数组的

可是这没有任何意思,由于它不能生成一个数组对象,也就是说以上代码只是把一个string类型的数组类和long类型的数组类加载到类内存中,并不能经过newinstance方法生成一个实例对象,由于它没有定义数组的长度,没有长度的数组是不容许存在的。

可是!能够用使用array数组反射类来动态加载:

由于数组比较特殊,要想动态建立和反问数组,基本的反射是没法实现的。因而java就专门定义来一个array数组反射工具类来实现动态探知数组的功能

10六、动态代理可使代理模式更加灵活

10七、动态代理可使装饰者模式更加灵活

10八、不须要太多关注反射效率

通常状况下反射并非性能的终极杀手,而代码结构混乱、可读性差则极可能会埋下隐患

第八章、异常

1十、提倡异常封装

1)提升系统的友好性

2)提升系统的可维护性

3)解决java异常机制自身的缺陷,抛多个异常

1十一、采用异常链传递参数

public class IOException extends Exception { public IOException() { super(); } //记录上一级异常 public IOException(String message, Throwable cause) { super(message, cause); } }

 1十二、受检异常尽量转化为非受检异常

1)受检异常使接口声明脆弱

oop要求咱们尽可能多的面向接口编程,能够提升代码的扩展性、稳定性等。可是一旦设计异常问题就不同了。好比一个接口抛出了异常a,随着业务的发展,该接口可能还会抛出异常b、异常c等。这会产生两个问题:

a)异常是主逻辑的补充逻辑,修改一个补充逻辑,就会致使主逻辑也被修改,也就是出现了实现类“逆影响”接口的情景,咱们知道实现类是不稳定的,而接口是稳定的,一旦定义了异常,则增长了接口的不稳定性

b)实现的类变动最终会影响到调用者,破坏了封装性,这也是迪米特法则所不能容忍的(设计模式6原则:一个对象应该对其余对象保持最少的了解)

2)受检异常使代码的可读性下降

3)受检异常增长了开发工做量

咱们知道,异常须要封装和传递,只有封装才能让异常更容易理解,上层模块才能更好的处理,可这也会致使低层级的异常没完没了的封装,无故加剧了开发的工做量。可是咱们也不能把全部的受检异常转化为非受检异常,缘由是在编码期上层模块不知道下层模块会抛出何种非受检异常,只有经过规则或文档来约束,能够这样说:

受检异常:法律下的自由

非受检异常:协约性质的自由

受检异常威胁到系统的安全性、稳定性、可靠性、正确性时,不能转换为非受检异常

11三、不要在finally块中处理返回值

1)覆盖了try代码块中的return返回值

在代码中加上try代码块就标志着运行时会有一个throwable线程监视着该方法的运行,若出现异常,则交由异常逻辑处理。

a)finally中修改基本数据类型返回值。返回值不会变化

方法在栈内存中运行,而且会按照‘先进后出’的原则执行,当dostuff方法执行完return a时,此方法的返回值已经肯定是int类型1,此后finally代码块再修改a的值已经于dostuff返回值没有任何关系了

b)finally中修改基本引用类型返回值。返回值会变化

返回李四。person是一个引用对象,在try代码块中的返回值的person对象的地址。

2)屏蔽异常

异常线程在监视到有异常发生时,就会登记当前的异常类型为dataformatexception,可是当执行finally代码块时,则会重新为dostuff方法赋值,也就是告诉调用者‘该方法执行正确,没有产生异常,返回值是1’

11四、不要在构造函数中抛出异常

1)加剧了上层代码编写者的负担

只能经过文档约束来告知上层代码有异常

2)致使子类代码膨胀

子类的无参构造函数默认调用的是父类的构造函数,因此子类的无参构造也必须抛出该异常或父类

3)违背来里氏替换原则(父类能出现的地方子类就能够出现,并且将父类替换为子类也不会产生任何异常)

      若是子类抛出的异常比父类抛出的异常范围大,则没法直接直接替换

4)子类构造函数扩展受限

  子类存在的缘由就是指望实现并扩展父类的逻辑,可是父类构造函数抛出异常却会让子类构造函数的灵活性大大下降

11五、使用throwable得到栈信息

aop编程能够很轻松的控制一个方法调用哪些类,也能控制哪些方法容许被调用,通常来讲切面编程只能控制到方法级别,不能实现代码级别的植入,好比一个方法被类A调用时放回1,在类B调用时放回0,这就要求被调用者具备识别调用者的能力。在这种状况下,可使用throwable得到栈信息,而后鉴别调用者并分别输出

11六、异常只为异常服务

不要包含业务流转

11七、多使用异常,把性能问题放一边

java的异常处理机制确实比较慢,单单从对象的建立来讲,new一个ioexception会比string慢5倍,由于它要执行fillinstatcktrace方法,要记录当前栈的快照,而string类则要直接申请一个内存建立对象。并且,异常类是不能缓存的,指望预先创建大量的异常对象是不可能的。(在jdk1.6,一个异常对象建立的时间1.4毫秒)

第九章、多线程和并发

11八、不推荐覆写start方法

从多线程的设计思想来讲。run方法是业务的处理逻辑,start是启动一个线程,并执行run方法

11九、启动线程前stop方法是不可靠的

stop():对于未启动的线程(线程状态为new),会设置其标志位为不可启动,而其余的状态则是直接中止

start():会先启动线程,再判断标志位,若是标志位是不可启动,则中止线程

会有一个时间差

120、不使用stop方法中止线程

1)stop方法是过期的

2)stop方法会致使代码逻辑不完整(好比说stop时还没释放io资源等等)

3)stop方法会破坏原子逻辑(会直接释放全部锁,致使原子逻辑受损)

12一、线程优先级只使用三个等级

线程的优先级(priority)决定了线程得到cpu运行的机会,优先级越高得到的运行机会越大,优先级越低得到的机会越小。但不保证顺序执行。thread类中设置了三个优先级,建议使用优先常量,而不是1到10随机的数字。

class thread{ /** * The minimum priority that a thread can have. */ public final static int MIN_PRIORITY = 1; /** * The default priority that is assigned to a thread. */ public final static int NORM_PRIORITY = 5; /** * The maximum priority that a thread can have. */ public final static int MAX_PRIORITY = 10; }

12二、使用线程异常处理器提高系统可靠性

jdk1.5之后,在thread类中增长了setUncaughtExceptionHandler方法,实现了线程异常的捕捉和处理

其实比较鸡肋

12三、volatile不能保证数据同步

volatile关键字比较少用,缘由

1)java1.5以前该关键字在不一样的操做系统上有不一样的表现,所带来的问题是移植性比较差;

2)只保证了可见性,不保证原子性

12四、异步运算考虑使用callable接口

1)尽量多地占用系统资源,提供快速运算??

2)能够监控线程执行的状况,好比是否执行完毕,是否有返回值,是否有异常等

3)能够为用户提供更好的支持,好比计算进度

12五、优先选择线程池

12六、适时选择不一样的线程池来实现

12七、lock于synchronized是不同的

12八、预防线程死锁

死锁须要4个条件

1)互斥条件:一个资源每次只能被一个线程使用

2)资源独占条件:一个线程因请求资源而阻塞时,对已得到的资源保持不放

3)不剥夺条件:线程已得到的资源在未使用完以前,不能强行剥夺

4)循环等待条件:若干线程之间造成一种头尾相接的循环等待资源关系

解决:

1)减小资源共享

2) 使用自旋锁

lock.trylock(1,TimeUnit.SECONDS)必定时间内获取不到锁则放弃

12九、适当设置阻塞队列长度

130、使用countdownlatch协调自线程

13一、cyclicbarrier让多线程齐步走

功能与countdownlotch相似,增长了子线程结束后的处理线程

第十章、性能和效率

13二、提高java性能的基本方法

1)不要在循环条件中计算

2)尽量把变量、方法声明为fianl static类型

3)缩小变量的做用范围(加快gc)

4)使用stringbuilder stringbuffer

5)使用非线性检索

6)覆写exception的fillinstacktrace方法

7)不创建冗余对象

这个方法是用来记录异常时的栈信息的,很是耗时,若是不关注能够覆盖之,会使性能提高10倍以上

13三、若非必要,不要克隆对象

经过clone方法生成一个对象时,就会再也不执行构造函数了,只是再内存中进行数据块的拷贝,此方法看上去彷佛应该比new的性能好不少,可是java的缔造者们也认识到二八原则,80%的对象是经过new关键字建立出来的,因此对new再生成对象时作了充分的性能优化,事实上,通常状况下new生成的对象clone生成的性能方面要好不少

13四、推荐使用望闻问切的方式诊断性能

??????

13五、必须定义性能衡量标准

13六、枪打出头鸟--解决首要系统性能问题

??????

13七、调整jvm参数以提高性能

13八、性能是个大‘咕咚’

?????

第11章、开源世界

13九、大胆采用开源工具

140、推荐使用guava扩展工具包

14二、apache扩展包

14三、推荐使用joda日期时间扩展包

14四、能够选择多种collections扩展

。。。。后面的就不说了 淡疼

 

收藏
  • 人气文章
  • 最新文章
  • 下载排行榜
  • 热门排行榜