for (int i = 0; i < args.length; i++) {
}
更改为:
for (int i = 0,index=args.length; i < index; i++) {
}
原理:每次在i++的时候都会重新计算一次args.length,优化之后只会计算一次
例如最常用的ArrayList,HashMap
List
Map
例如:
String str = “abc”;
String str2 = str + “ccd”;
jvm会在堆内存中开辟3个空间,1为“abc”,2为“ccd”,3为“abcccd”,最终str2指向,1和2因为没有被引用,会在GC回收机制内被回收,而GC的开销是相当大的,所以应尽量避免。
使用StringBuffer:
StringBuffer str =“abc”;
str.append(“ccd”);
jvm只会在堆空间中开辟一个空间“abc”,执行append时只会在“abc”的空间上+“ccd”
因此避免了GC的回收,也避免了内存的浪费
如果有线程安全的考虑使用StringBuffer,无则使用StringBuilder,线程安全也是一个比较高的开销
例如:
Brand brand = new Brand();
brand.setImgUrl("dddddddddd");
// brand.setName("HFanss");
String ss = "HFanss";
if (brand.getName().equals(ss)) {
System.err.println("相同");
}else
{
System.err.println("不相同");
}
抛出空指针异常,应修改为:
if (ss.equals(brand.getName()))
这时候会输出 不相同。
原理:equals的源码解释 当比较对象(常量ss)为空时,抛出空指针异常,
而被比较对象(brand.getName())为空时,则直接以 false结束
如:
String str = "HFanss";
if ("2".equals(status)) {
list.add(str);
}
应该为:
if ("2".equals(status)) {
String str = "HFanss";
list.add(str);
}
原理:这个应该很容易看懂的,当if不成立时,创建的字符串就没用了,面临GC回收,应该有效避免,写在if内部
如:
int a = 2;
int b = 16;
System.err.println(a<<5);//等同于 2*2*2*2*2*2 即2*32
System.err.println(b>>2);//等同于 16/2/2 即16/4
如:
List
for (int i = 0; i < 1000; i++)
{
Object obj = new Object();
list.add(obj);
}
应该为:
List
Object obj = null;
for (int i = 0; i < 1000; i++)
{
obj = new Object();
list.add(obj);
}
原理:我们的目的只是list.add(obj)这一步,
前者obj引用会在栈空间中有1000个,但是最终只会用到1个,
后者obj引用在栈空间只有1个
当某个对象被定义为static变量所引用,那么GC通常是不会回收这个对象所占有的内存,如
public class A{
private static B b = new B();
}
此时静态变量b的生命周期与A类同步,如果A类不会卸载,那么b对象会常驻内存,直到程序终止。
带有final修饰符的类是不可派生的。在JAVA核心API中,有许多应用final的例子,例如java、lang、String,为String类指定final防止了使用者覆盖length()方法。另外,如果一个类是final的,则该类所有方法都是final的。java编译器会寻找机会内联(inline)所有的final方法(这和具体的编译器实现有关),此举能够使性能平均提高50%。
如:让访问实例内变量的getter/setter方法变成”final:
简单的getter/setter方法应该被置成final,这会告诉编译器,这个方法不会被重载,例子:
class MAF {
public void setSize (int size) {
_size = size;
}
private int _size;
}
更正:
class DAF_fixed {
final public void setSize (int size) {
_size = size;
}
private int _size;
}
一般有3种方法
Integer s = 5;
s.toString();//s为null报空指针异常
String.valueOf(s);//源码显示调用了Integer.toString()方法,而且会在调用前做空判断
s+“”;//源码显示使用StringBuilder实现,先用append方法拼接,再用toString()方法对比而言,直接调用最底层的toString()方法无疑是效率最高的
System.arraycopy() 要比通过循环来复制数组快的多。
Map
for( Entry
{
String appFieldDefId = entry.getKey();
String[] values = entry.getValue();
}
利用散列值取出相应的Entry做比较得到结果,取得entry的值之后直接取key和value。
String str = "hello";
上面这种方式会创建一个“hello”字符串,而且JVM的字符缓存池还会缓存这个字符串;
String str = new String("hello");
此时程序除创建字符串外,str所引用的String对象底层还包含一个char[]数组,这个char[]数组依次存放了h,e,l,l,o
大部分时,方法局部引用变量所引用的对象会随着方法结束而变成垃圾,因此,大部分时候程序无需将局部,引用变量显式设为null。
例如:
Public void test(){
Object obj = new Object();
……
Obj=null;
}
上面这个就没必要了,随着方法test()的执行完成,程序中obj引用变量的作用域就结束了。但是如果是改成下面:
Public void test(){
Object obj = new Object();
……
Obj=null;
//执行耗时,耗内存操作;或调用耗时,耗内存的方法
……
}
这时候就有必要将obj赋值为null,可以尽早的释放对Object对象的引用。
除非是必须的,否则应该避免使用split,split由于支持正则表达式,所以效率比较低,如果是频繁的几十,几百万的调用将会耗费大量资源,如果确实需要频繁的调用split,可以考虑使用apache的StringUtils.split(string,char),频繁split的可以缓存结果。
默认情况下,调用类的构造函数时,java会把变量初始化成确定的值,所有的对象被设置成null,整数变量设置成0,float和double变量设置成0.0,逻辑值设置成false。当一个类从另一个类派生时,这一点尤其应该注意,因为用new关键字创建一个对象时,构造函数链中的所有构造函数都会被自动调用。
这里有个注意,给成员变量设置初始值但需要调用其他方法的时候,最好放在一个方法。比如initXXX()中,因为直接调用某方法赋值可能会因为类尚未初始化而抛空指针异常,如:public int state = this.getState()。
Error是获取系统错误的类,或者说是虚拟机错误的类。不是所有的错误Exception都能获取到的,虚拟机报错Exception就获取不到,必须用Error获取。
体系上的优化,分为 结构优化,日志优化,可读性优化,异常优化
A. action层尽量不要做参数的校验和逻辑书写,它只负责请求的转发和响应,入参和出参
B. Service层逻辑要清晰,尽量不要有if,for的出现,全部封装到公共方法去调用
C. DAO层只提供持久层相关操作,如封装参数进map供持久层使用,尽量不要有逻辑在里面,所有的逻辑应都在service里完成
A. 方法开始后、结束前书写日志
B. 抓取异常时书写日志
C. 特殊情况时书写。如需要提前return时
A. 类、方法必须要有注释
B. 在一些比较大的逻辑前加上注释
C. 一个完美的service层,应逻辑清晰,一行代码代表一个逻辑,通篇下来可读性非常强
A. 异常应只用来进行错误处理,而不是逻辑处理(异常也是高开销的操作)
B. 善用多种异常,但是在service层应只有一个 try cath来抓取多个异常,并分别处理
C. 异常理应在service层全部处理完,不能再继续往上抛(理论上可以接续抛,但service本来就是处理逻辑的,尽量在本层处理完)
---------------长按二维码关注程序媛小姐姐公众号有更多彩蛋哦---------------